pycui commited on
Commit
babeaf6
1 Parent(s): 5e5cb0d

Add RealChar deployment for HuggingFace (V0)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. CHANGELOG.md +22 -0
  2. Dockerfile +22 -0
  3. LICENSE +21 -0
  4. README.md +276 -11
  5. alembic.ini +110 -0
  6. alembic/README +1 -0
  7. alembic/__pycache__/env.cpython-311.pyc +0 -0
  8. alembic/env.py +92 -0
  9. alembic/script.py.mako +24 -0
  10. alembic/versions/0f355a71adbb_added_interaction_table.py +32 -0
  11. alembic/versions/27fe156a6d72_change_schema_to_unicode.py +28 -0
  12. alembic/versions/3821f7adaca9_add_session_id.py +25 -0
  13. alembic/versions/9ed6d1431c1d_add_platform_and_action_types.py +28 -0
  14. alembic/versions/__pycache__/0f355a71adbb_added_interaction_table.cpython-311.pyc +0 -0
  15. alembic/versions/__pycache__/27fe156a6d72_change_schema_to_unicode.cpython-311.pyc +0 -0
  16. alembic/versions/__pycache__/3821f7adaca9_add_session_id.cpython-311.pyc +0 -0
  17. alembic/versions/__pycache__/9ed6d1431c1d_add_platform_and_action_types.cpython-311.pyc +0 -0
  18. alembic/versions/__pycache__/c3a93ef3de5d_drop_client_id_column.cpython-311.pyc +0 -0
  19. alembic/versions/__pycache__/ead242c61258_added_user_table.cpython-311.pyc +0 -0
  20. alembic/versions/__pycache__/eced1ae3918a_add_string_user_id.cpython-311.pyc +0 -0
  21. alembic/versions/ead242c61258_added_user_table.py +32 -0
  22. alembic/versions/eced1ae3918a_add_string_user_id.py +35 -0
  23. cli.py +77 -0
  24. client/README.md +11 -0
  25. client/cli.py +278 -0
  26. client/mobile/ios/.gitignore +175 -0
  27. client/mobile/ios/rac/rac.xcodeproj/project.pbxproj +597 -0
  28. client/mobile/ios/rac/rac.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  29. client/mobile/ios/rac/rac.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  30. client/mobile/ios/rac/rac.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +140 -0
  31. client/mobile/ios/rac/rac/Assets/Assets.xcassets/AccentColor.colorset/Contents.json +20 -0
  32. client/mobile/ios/rac/rac/Assets/Assets.xcassets/AppIcon.appiconset/AppIcon.png +0 -0
  33. client/mobile/ios/rac/rac/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
  34. client/mobile/ios/rac/rac/Assets/Assets.xcassets/Contents.json +6 -0
  35. client/mobile/ios/rac/rac/Assets/Assets.xcassets/logo.imageset/Contents.json +25 -0
  36. client/mobile/ios/rac/rac/Assets/Assets.xcassets/logo.imageset/logo.svg +11 -0
  37. client/mobile/ios/rac/rac/Assets/Assets.xcassets/logo.imageset/logo_dark.svg +11 -0
  38. client/mobile/ios/rac/rac/Assets/Assets.xcassets/menu.imageset/Contents.json +16 -0
  39. client/mobile/ios/rac/rac/Assets/Assets.xcassets/menu.imageset/menu.svg +9 -0
  40. client/mobile/ios/rac/rac/Assets/Assets.xcassets/message.imageset/Contents.json +16 -0
  41. client/mobile/ios/rac/rac/Assets/Assets.xcassets/message.imageset/message.svg +5 -0
  42. client/mobile/ios/rac/rac/Assets/Assets.xcassets/power.imageset/Contents.json +16 -0
  43. client/mobile/ios/rac/rac/Assets/Assets.xcassets/power.imageset/power.svg +5 -0
  44. client/mobile/ios/rac/rac/Assets/Assets.xcassets/stop.imageset/Contents.json +16 -0
  45. client/mobile/ios/rac/rac/Assets/Assets.xcassets/stop.imageset/stop.svg +5 -0
  46. client/mobile/ios/rac/rac/Assets/Assets.xcassets/voice.imageset/Contents.json +16 -0
  47. client/mobile/ios/rac/rac/Assets/Assets.xcassets/voice.imageset/voice.svg +3 -0
  48. client/mobile/ios/rac/rac/Assets/Prompt-Medium.ttf +0 -0
  49. client/mobile/ios/rac/rac/Assets/Prompt-Regular.ttf +0 -0
  50. client/mobile/ios/rac/rac/Assets/Prompt-SemiBold.ttf +0 -0
CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ChangeLog
2
+
3
+ ## [v0.0.1] - 2023-07-19
4
+ Release Highlights:
5
+
6
+ ### Product releases and updates:
7
+ - iOS App TestFlight public beta (link https://testflight.apple.com/join/JA6p9sZQ)
8
+ - Rewrite Web codebase from vanilla JavaScript to use React framework w/ Javascript
9
+ - Support Unicode in chat messages
10
+ - Various UI refinements
11
+
12
+ ### Integration updates:
13
+ - Support Azure OpenAI
14
+
15
+ ### Observability and quality updates:
16
+ - Support Integration with LangSmith
17
+ - Reduce Docker rebuild time to ~2 seconds
18
+ - Support string based user ID
19
+ - Support Session ID, Platform, Action Type in database records.
20
+
21
+ ### New Tutorial:
22
+ [How to make your own AI character and run it locally](https://youtu.be/meg5Q8vdWeQ)
Dockerfile ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:slim
2
+
3
+ # Install system-level dependencies
4
+ RUN apt-get update && apt-get install -y build-essential portaudio19-dev libffi-dev libssl-dev ffmpeg
5
+
6
+ WORKDIR /realtime_ai_character
7
+
8
+ # Install Python dependencies
9
+ COPY requirements.txt /realtime_ai_character
10
+ RUN pip install -r /realtime_ai_character/requirements.txt
11
+
12
+ # Copy the project files
13
+ COPY ./ /realtime_ai_character
14
+
15
+ # Expose 7860 port from the docker image.
16
+ EXPOSE 7860
17
+
18
+ # Make the entrypoint script executable
19
+ RUN chmod +x /realtime_ai_character/entrypoint.sh
20
+
21
+ # Run the application
22
+ CMD ["/bin/sh", "/realtime_ai_character/entrypoint.sh"]
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2023 shaun
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,11 +1,276 @@
1
- ---
2
- title: RealChar
3
- emoji:
4
- colorFrom: pink
5
- colorTo: pink
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
- ---
10
-
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # <img src="./realtime_ai_character/static/realchar.svg" height="24px" style="padding-top:4px"/>RealChar. - Your Realtime AI Character
2
+ <br/>
3
+ <div align="center">
4
+ <img src="./realtime_ai_character/static/logo.png" alt="RealChar-logo" width="80%" style="padding: 40px"/>
5
+ </div>
6
+ <br/>
7
+ <p align="center">
8
+ 🎙️🤖<em>Create, customize and talk to your AI Character/Companion in realtime</em>🎙️🤖
9
+ </p>
10
+
11
+ <div align="center">
12
+ <a href="https://discord.gg/e4AYNnFg2F">
13
+ <img src="https://img.shields.io/badge/discord-join%20chat-blue.svg?style=for-the-badge" alt="Join our Discord" height="20">
14
+ </a>
15
+ <a href="https://twitter.com/agishaun">
16
+ <img alt="Twitter Follow" src="https://img.shields.io/twitter/follow/agishaun?style=for-the-badge" height="20">
17
+ <a href="https://github.com/Shaunwei/RealChar">
18
+ <img alt="GitHub" src="https://img.shields.io/github/stars/Shaunwei/RealChar?style=for-the-badge&color=gold" height="20">
19
+ </a>
20
+ <a href="https://github.com/Shaunwei/RealChar/commits/main">
21
+ <img alt="GitHub" src="https://img.shields.io/github/last-commit/Shaunwei/RealChar/main?style=for-the-badge" height="20">
22
+ </a>
23
+ <a href="https://github.com/Shaunwei/RealChar/blob/main/README.md" target="_blank">
24
+ <img src="https://img.shields.io/static/v1?label=license&message=MIT&color=green&style=for-the-badge" alt="License" height="20">
25
+ </a>
26
+ <a href="https://hub.docker.com/repository/docker/shaunly/real_char/general" target="_blank">
27
+ <img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/shaunly/real_char?style=for-the-badge" height="20">
28
+ </a>
29
+ </div>
30
+
31
+ ## ✨ Demo
32
+ Try our site at [RealChar.ai](https://realchar.ai/)
33
+
34
+ (We are also beta-testing our iOS mobile app📱! Sign up [here](https://testflight.apple.com/join/JA6p9sZQ))
35
+
36
+ ### Demo 1 - with AI Elon about cage fight!
37
+
38
+ https://github.com/Shaunwei/RealChar/assets/5101573/5de0b023-6cf3-4947-84cb-596f429d109e
39
+
40
+ ### Demo 2 - with AI Raiden about AI and "real" memory
41
+
42
+ https://github.com/Shaunwei/RealChar/assets/5101573/62a1f3d1-1166-4254-9119-97647be52c42
43
+
44
+
45
+
46
+ __Demo settings: Web, GPT4, ElevenLabs with voice clone, Chroma, Google Speech to Text__
47
+
48
+ ## 🎯 Key Features
49
+ - **Easy to use**: No coding required to create your own AI character.
50
+ - **Customizable**: You can customize your AI character's personality, background, and even voice
51
+ - **Realtime**: Talk to or message your AI character in realtime
52
+ - **Multi-Platform**: You can talk to your AI character on web, terminal and mobile(Yes. we open source our mobile app)
53
+ - **Most up-to-date AI**: We use the most up-to-date AI technology to power your AI character, including OpenAI, Anthropic Claude 2, Chroma, Whisper, ElevenLabs, etc.
54
+ - **Modular**: You can easily swap out different modules to customize your flow. Less opinionated, more flexible. Great project to start your AI Engineering journey.
55
+
56
+ ## 🔬 Tech stack
57
+ <div align="center">
58
+ <img src="https://storage.googleapis.com/assistly/static/realchar/techstack.png" alt="RealChar-tech-stack" width="100%" style="padding: 20px"/>
59
+ </div>
60
+
61
+ - ✅**Web**: [Vanilla JS](http://vanilla-js.com/), [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
62
+ - ✅**Mobile**: [Swift](https://developer.apple.com/swift/), [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
63
+ - ✅**Backend**: [FastAPI](https://fastapi.tiangolo.com/), [SQLite](https://www.sqlite.org/index.html), [Docker](https://www.docker.com/)
64
+ - ✅**Data Ingestion**: [LlamaIndex](https://www.llamaindex.ai/), [Chroma](https://www.trychroma.com/)
65
+ - ✅**LLM Orchestration**: [LangChain](https://langchain.com/), [Chroma](https://www.trychroma.com/)
66
+ - ✅**LLM**: [OpenAI GPT3.5/4](https://platform.openai.com/docs/api-reference/chat), [Anthropic Claude 2](https://docs.anthropic.com/claude/docs/getting-started-with-claude)
67
+ - ✅**Speech to Text**: [Local Whisper](https://github.com/openai/whisper), [OpenAI Whisper API](https://platform.openai.com/docs/api-reference/audio), [Google Speech to Text](https://cloud.google.com/speech-to-text/docs#docs)
68
+ - ✅**Text to Speech**: [ElevenLabs](https://beta.elevenlabs.io/)
69
+ - ✅**Voice Clone**: [ElevenLabs](https://beta.elevenlabs.io/voice-lab)
70
+
71
+ ## 📚 Comparison with existing products
72
+ <div align="center">
73
+ <img src="https://storage.googleapis.com/assistly/static/realchar/compare.png">
74
+ </div>
75
+
76
+
77
+ ## 👨‍🚀 Prerequisites
78
+
79
+ Before you begin setting up this project, please ensure you have completed the following tasks:
80
+
81
+ ### 0. Setup Tutorial
82
+
83
+ - [Tutorial - YouTuBe](https://www.youtube.com/watch?v=Q16ZH3kJWxw)
84
+
85
+ ### 1. LLM - OpenAI API Token
86
+ <details><summary>👇click me</summary>
87
+ This application utilizes the OpenAI API to access its powerful language model capabilities. In order to use the OpenAI API, you will need to obtain an API token.
88
+
89
+ To get your OpenAI API token, follow these steps:
90
+
91
+ 1. Go to the [OpenAI website](https://beta.openai.com/signup/) and sign up for an account if you haven't already.
92
+ 2. Once you're logged in, navigate to the [API keys page](https://beta.openai.com/account/api-keys).
93
+ 3. Generate a new API key by clicking on the "Create API Key" button.
94
+ 4. Copy the API key and store it safely.
95
+ 5. Add the API key to your environment variable, e.g. `export OPENAI_API_KEY=<your API key>`
96
+
97
+ (Optional) To use Azure OpenAI API instead, refer to the following section:
98
+
99
+ 1. Set API type
100
+ `export OPENAI_API_TYPE=azure`
101
+
102
+ If you want to use the earlier version `2023-03-15-preview`:
103
+
104
+ `export OPENAI_API_VERSION=2023-03-15-preview`
105
+
106
+ 2. To set the base URL for your Azure OpenAI resource.
107
+ You can find this in the Azure portal under your Azure OpenAI resource.
108
+
109
+ `export OPENAI_API_BASE=https://your-base-url.openai.azure.com`
110
+
111
+ 3. To set the OpenAI model deployment name for your Azure OpenAI resource.
112
+
113
+ `export OPENAI_API_MODEL_DEPLOYMENT_NAME=gpt-35-turbo-16k`
114
+
115
+ 4. To set the OpenAIEmbeddings model deployment name for your Azure OpenAI resource.
116
+
117
+ `export OPENAI_API_EMBEDDING_DEPLOYMENT_NAME=text-embedding-ada-002`
118
+
119
+ </details>
120
+
121
+ ### 1.1 (Optional) Prepare LLM - Anthropic(Claude 2) API Token
122
+ <details><summary>👇click me</summary>
123
+
124
+ To get your Anthropic API token, follow these steps:
125
+
126
+ 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.
127
+ 2. Once you're logged in, navigate to the [API keys page](https://console.anthropic.com/account/keys).
128
+ 3. Generate a new API key by clicking on the "Create Key" button.
129
+ 4. Copy the API key and store it safely.
130
+ 5. Add the API key to your environment variable, e.g. `export ANTHROPIC_API_KEY=<your API key>`
131
+ </details>
132
+
133
+ ### 2. (Optional) Prepare Speech to Text - Google Cloud API
134
+ <details><summary>👇click me</summary>
135
+
136
+ To get your Google Cloud API credentials.json, follow these steps:
137
+
138
+ 1. Go to the [GCP website](https://cloud.google.com/speech-to-text/docs/before-you-begin) and sign up for an account if you haven't already.
139
+ 2. Follow the guide to create a project and enable Speech to Text API
140
+ 3. Put `google_credentials.json` in the root folder of this project. Check [GCP website](https://cloud.google.com/speech-to-text/docs/before-you-begin#set_your_authentication_environment_variable)
141
+ 4. Change `SPEECH_TO_TEXT_USE` to use `GOOGLE` in your `.env` file
142
+ </details>
143
+
144
+
145
+ ### 3. Prepare Text to Speech - ElevenLabs API Key
146
+ <details><summary>👇click me</summary>
147
+ 1. Creating an ElevenLabs Account
148
+ Visit [ElevenLabs](https://beta.elevenlabs.io/) to create an account. You'll need this to access the text to speech and voice cloning features.
149
+
150
+ 2. In your Profile Setting, you can get an API Key. Save it in a safe place.
151
+
152
+ 3. Set API key in your .env file:
153
+ ```
154
+ ELEVEN_LABS_API_KEY=<api key>
155
+ ```
156
+ </details>
157
+
158
+ ## 💿 Installation via Python
159
+ - **Step 1**. Clone the repo
160
+ ```sh
161
+ git clone https://github.com/Shaunwei/RealChar.git && cd RealChar
162
+ ```
163
+ - **Step 2**. Install requirements
164
+ - Install [portaudio](https://people.csail.mit.edu/hubert/pyaudio/) and [ffmpeg](https://ffmpeg.org/download.html) for audio
165
+ ```sh
166
+ # for mac
167
+ brew install portaudio
168
+ brew install ffmpeg
169
+ ```
170
+ ```sh
171
+ # for ubuntu
172
+ sudo apt update
173
+ sudo apt install portaudio19-dev
174
+ sudo apt install ffmpeg
175
+ ```
176
+ - Then install all python requirements
177
+ ```sh
178
+ pip install -r requirements.txt
179
+ ```
180
+ - **Step 3**. Create an empty [sqlite](https://www.sqlite.org/index.html) database if you have not done so before
181
+ ```sh
182
+ sqlite3 test.db "VACUUM;"
183
+ ```
184
+ - **Step 4**. Run db upgrade
185
+ ```sh
186
+ alembic upgrade head
187
+ ```
188
+ - **Step 5**. Setup `.env`: update API keys and select module
189
+ ```sh
190
+ cp .env.example .env
191
+ ```
192
+ - **Step 6**. Run server with `cli.py` or use uvicorn directly
193
+ ```sh
194
+ python cli.py run-uvicorn
195
+ # or
196
+ uvicorn realtime_ai_character.main:app
197
+ ```
198
+ - **Step 7**. Run client:
199
+ - Use **GPT4** for better conversation and **Wear headphone** for best audio(avoid echo)
200
+ - There are two ways to access the web client:
201
+ - **Option 1**: Open your web browser and navigate to http://localhost:8000 (NOT 0.0.0.0:8000)
202
+ - **Option 2**: Running the client in React.
203
+ ```sh
204
+ cd client/web
205
+ npm install
206
+ npm start
207
+ ```
208
+ After running these commands, a local development server will start, and your default web browser will open a new tab/window pointing to this server (usually http://localhost:3000).
209
+ - (Optional) Terminal client: Run the following command in your terminal
210
+ ```sh
211
+ python client/cli.py
212
+ ```
213
+ - (Optional) mobile client: open `client/mobile/ios/rac/rac.xcodeproj/project.pbxproj` in Xcode and run the app
214
+ - **Step 8**. Select one character to talk to, then start talking
215
+
216
+
217
+ ## (Optional) 📀 Installation via Docker
218
+ <details><summary>👇click me</summary>
219
+
220
+ 1. Docker image: you can use our docker image directly
221
+ ```sh
222
+ docker pull shaunly/real_char:latest
223
+ ```
224
+ (Or you want build yourself) Build docker image
225
+ ```sh
226
+ python cli.py docker-build
227
+ ```
228
+ If you have issues with docker (especially on a non-Linux machine), please refer to https://docs.docker.com/get-docker/ (installation) and https://docs.docker.com/desktop/troubleshoot/overview/ (troubleshooting).
229
+ 2. Run docker image with `.env` file
230
+ ```sh
231
+ python cli.py docker-run
232
+ ```
233
+
234
+ 3. Go to http://localhost:8000 (NOT 0.0.0.0:8000) to start talking or use terminal client
235
+ ```sh
236
+ python client/cli.py
237
+ ```
238
+
239
+ </details>
240
+
241
+ <br/>
242
+
243
+ ## 🆕! LangSmith integration
244
+ <details><summary>👇click me</summary>
245
+
246
+ If you have access to LangSmith, you can edit these environment variables to enable:
247
+ ```
248
+ LANGCHAIN_TRACING_V2=false # default off
249
+ LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
250
+ LANGCHAIN_API_KEY=YOUR_LANGCHAIN_API_KEY
251
+ LANGCHAIN_PROJECT=YOUR_LANGCHAIN_PROJECT
252
+ ```
253
+ And it should work out of the box.
254
+
255
+ </details>
256
+
257
+ <br/>
258
+
259
+ ## 📍 Roadmap
260
+ - [x] Launch v0.0.1 and build a community
261
+ - [x] Move away from Vanilla JS
262
+ - [x] Launch mobile app (iOS TestFlight Beta link: https://testflight.apple.com/join/JA6p9sZQ)
263
+ - [ ] Add authentication for customization
264
+ - [ ] Allow selecting different LLM
265
+ - [ ] Add ability to add community characters
266
+
267
+ ## 🫶 Contribute to RealChar
268
+ Please check out our [Contribution Guide](contribute.md)!
269
+
270
+ ## 💪 Contributors
271
+ <a href="https://github.com/Shaunwei/RealChar">
272
+ <img src="https://contrib.rocks/image?repo=Shaunwei/RealChar" />
273
+ </a>
274
+
275
+ ## 🎲 Community
276
+ - Join us on [Discord](https://discord.gg/e4AYNnFg2F)
alembic.ini ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # A generic, single database configuration.
2
+
3
+ [alembic]
4
+ # path to migration scripts
5
+ script_location = alembic
6
+
7
+ # template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
8
+ # Uncomment the line below if you want the files to be prepended with date and time
9
+ # see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
10
+ # for all available tokens
11
+ # file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
12
+
13
+ # sys.path path, will be prepended to sys.path if present.
14
+ # defaults to the current working directory.
15
+ prepend_sys_path = .
16
+
17
+ # timezone to use when rendering the date within the migration file
18
+ # as well as the filename.
19
+ # If specified, requires the python-dateutil library that can be
20
+ # installed by adding `alembic[tz]` to the pip requirements
21
+ # string value is passed to dateutil.tz.gettz()
22
+ # leave blank for localtime
23
+ # timezone =
24
+
25
+ # max length of characters to apply to the
26
+ # "slug" field
27
+ # truncate_slug_length = 40
28
+
29
+ # set to 'true' to run the environment during
30
+ # the 'revision' command, regardless of autogenerate
31
+ # revision_environment = false
32
+
33
+ # set to 'true' to allow .pyc and .pyo files without
34
+ # a source .py file to be detected as revisions in the
35
+ # versions/ directory
36
+ # sourceless = false
37
+
38
+ # version location specification; This defaults
39
+ # to alembic/versions. When using multiple version
40
+ # directories, initial revisions must be specified with --version-path.
41
+ # The path separator used here should be the separator specified by "version_path_separator" below.
42
+ # version_locations = %(here)s/bar:%(here)s/bat:alembic/versions
43
+
44
+ # version path separator; As mentioned above, this is the character used to split
45
+ # version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
46
+ # If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
47
+ # Valid values for version_path_separator are:
48
+ #
49
+ # version_path_separator = :
50
+ # version_path_separator = ;
51
+ # version_path_separator = space
52
+ version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
53
+
54
+ # set to 'true' to search source files recursively
55
+ # in each "version_locations" directory
56
+ # new in Alembic version 1.10
57
+ # recursive_version_locations = false
58
+
59
+ # the output encoding used when revision files
60
+ # are written from script.py.mako
61
+ # output_encoding = utf-8
62
+
63
+ sqlalchemy.url = sqlite:///./test.db
64
+
65
+
66
+ [post_write_hooks]
67
+ # post_write_hooks defines scripts or Python functions that are run
68
+ # on newly generated revision scripts. See the documentation for further
69
+ # detail and examples
70
+
71
+ # format using "black" - use the console_scripts runner, against the "black" entrypoint
72
+ # hooks = black
73
+ # black.type = console_scripts
74
+ # black.entrypoint = black
75
+ # black.options = -l 79 REVISION_SCRIPT_FILENAME
76
+
77
+ # Logging configuration
78
+ [loggers]
79
+ keys = root,sqlalchemy,alembic
80
+
81
+ [handlers]
82
+ keys = console
83
+
84
+ [formatters]
85
+ keys = generic
86
+
87
+ [logger_root]
88
+ level = WARN
89
+ handlers = console
90
+ qualname =
91
+
92
+ [logger_sqlalchemy]
93
+ level = WARN
94
+ handlers =
95
+ qualname = sqlalchemy.engine
96
+
97
+ [logger_alembic]
98
+ level = INFO
99
+ handlers =
100
+ qualname = alembic
101
+
102
+ [handler_console]
103
+ class = StreamHandler
104
+ args = (sys.stderr,)
105
+ level = NOTSET
106
+ formatter = generic
107
+
108
+ [formatter_generic]
109
+ format = %(levelname)-5.5s [%(name)s] %(message)s
110
+ datefmt = %H:%M:%S
alembic/README ADDED
@@ -0,0 +1 @@
 
 
1
+ Generic single-database configuration.
alembic/__pycache__/env.cpython-311.pyc ADDED
Binary file (3.95 kB). View file
 
alembic/env.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from realtime_ai_character.models.user import User
2
+ from realtime_ai_character.models.interaction import Interaction
3
+ from realtime_ai_character.database.base import Base # import the Base model
4
+ from sqlalchemy import engine_from_config
5
+ from sqlalchemy import pool
6
+ from alembic import context
7
+ from logging.config import fileConfig
8
+ import sys
9
+ import os
10
+ from dotenv import load_dotenv
11
+
12
+ load_dotenv()
13
+
14
+ # Add the project root to the system path
15
+ root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
16
+ sys.path.append(root)
17
+
18
+ # import your models here
19
+
20
+ # this is the Alembic Config object, which provides access to the values
21
+ # within the .ini file in use.
22
+ config = context.config
23
+ database_url = os.getenv('DATABASE_URL') if os.getenv(
24
+ 'DATABASE_URL') else 'sqlite:///./test.db'
25
+ config.set_main_option('sqlalchemy.url', database_url)
26
+
27
+ # Interpret the config file for Python logging.
28
+ # This line sets up loggers basically.
29
+ fileConfig(config.config_file_name)
30
+
31
+ # add your model's MetaData object here
32
+ # for 'autogenerate' support
33
+ # from myapp import mymodel
34
+ # target_metadata = mymodel.Base.metadata
35
+ target_metadata = Base.metadata # use your Base metadata
36
+
37
+ # other values from the config, defined by the needs of env.py,
38
+ # can be acquired:
39
+ # my_important_option = config.get_main_option("my_important_option")
40
+ # ... etc.
41
+
42
+
43
+ def run_migrations_offline() -> None:
44
+ """Run migrations in 'offline' mode.
45
+
46
+ This configures the context with just a URL
47
+ and not an Engine, though an Engine is acceptable
48
+ here as well. By skipping the Engine creation
49
+ we don't even need a DBAPI to be available.
50
+
51
+ Calls to context.execute() here emit the given string to the
52
+ script output.
53
+
54
+ """
55
+ url = config.get_main_option("sqlalchemy.url")
56
+ context.configure(
57
+ url=url,
58
+ target_metadata=target_metadata,
59
+ literal_binds=True,
60
+ dialect_opts={"paramstyle": "named"},
61
+ )
62
+
63
+ with context.begin_transaction():
64
+ context.run_migrations()
65
+
66
+
67
+ def run_migrations_online() -> None:
68
+ """Run migrations in 'online' mode.
69
+
70
+ In this scenario we need to create an Engine
71
+ and associate a connection with the context.
72
+
73
+ """
74
+ connectable = engine_from_config(
75
+ config.get_section(config.config_ini_section, {}),
76
+ prefix="sqlalchemy.",
77
+ poolclass=pool.NullPool,
78
+ )
79
+
80
+ with connectable.connect() as connection:
81
+ context.configure(
82
+ connection=connection, target_metadata=target_metadata
83
+ )
84
+
85
+ with context.begin_transaction():
86
+ context.run_migrations()
87
+
88
+
89
+ if context.is_offline_mode():
90
+ run_migrations_offline()
91
+ else:
92
+ run_migrations_online()
alembic/script.py.mako ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """${message}
2
+
3
+ Revision ID: ${up_revision}
4
+ Revises: ${down_revision | comma,n}
5
+ Create Date: ${create_date}
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+ ${imports if imports else ""}
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = ${repr(up_revision)}
14
+ down_revision = ${repr(down_revision)}
15
+ branch_labels = ${repr(branch_labels)}
16
+ depends_on = ${repr(depends_on)}
17
+
18
+
19
+ def upgrade() -> None:
20
+ ${upgrades if upgrades else "pass"}
21
+
22
+
23
+ def downgrade() -> None:
24
+ ${downgrades if downgrades else "pass"}
alembic/versions/0f355a71adbb_added_interaction_table.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Added interaction table
2
+
3
+ Revision ID: 0f355a71adbb
4
+ Revises: ead242c61258
5
+ Create Date: 2023-06-26 22:07:19.624594
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = '0f355a71adbb'
14
+ down_revision = 'ead242c61258'
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.create_table('interactions',
21
+ sa.Column('id', sa.Integer(),
22
+ primary_key=True, index=True),
23
+ sa.Column('client_id', sa.Integer(), nullable=True),
24
+ sa.Column('client_message', sa.String(), nullable=True),
25
+ sa.Column('server_message', sa.String(), nullable=True),
26
+ sa.Column('timestamp', sa.DateTime(), nullable=True),
27
+ sa.PrimaryKeyConstraint('id')
28
+ )
29
+
30
+
31
+ def downgrade() -> None:
32
+ op.drop_table('interactions')
alembic/versions/27fe156a6d72_change_schema_to_unicode.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Change message schema to unicode
2
+
3
+ Revision ID: 27fe156a6d72
4
+ Revises: 9ed6d1431c1d
5
+ Create Date: 2023-07-18 22:32:03.388403
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = '27fe156a6d72'
14
+ down_revision = '9ed6d1431c1d'
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.add_column('interactions', sa.Column(
21
+ 'client_message_unicode', sa.Unicode(65535)))
22
+ op.add_column('interactions', sa.Column(
23
+ 'server_message_unicode', sa.Unicode(65535)))
24
+
25
+
26
+ def downgrade() -> None:
27
+ op.drop_column('interactions', 'client_message_unicode')
28
+ op.drop_column('interactions', 'server_message_unicode')
alembic/versions/3821f7adaca9_add_session_id.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Add session ID
2
+
3
+ Revision ID: 3821f7adaca9
4
+ Revises: 27fe156a6d72
5
+ Create Date: 2023-07-18 22:44:33.107380
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = '3821f7adaca9'
14
+ down_revision = '27fe156a6d72'
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.add_column('interactions', sa.Column(
21
+ 'session_id', sa.String(50), nullable=True))
22
+
23
+
24
+ def downgrade() -> None:
25
+ op.drop_column('interactions', 'session_id')
alembic/versions/9ed6d1431c1d_add_platform_and_action_types.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """add platform and action types
2
+
3
+ Revision ID: 9ed6d1431c1d
4
+ Revises: 0f355a71adbb
5
+ Create Date: 2023-07-18 00:31:05.044828
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = '9ed6d1431c1d'
14
+ down_revision = '0f355a71adbb'
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.add_column('interactions', sa.Column(
21
+ 'platform', sa.String(50), nullable=True))
22
+ op.add_column('interactions', sa.Column(
23
+ 'action_type', sa.String(50), nullable=True))
24
+
25
+
26
+ def downgrade() -> None:
27
+ op.drop_column('interactions', 'platform')
28
+ op.drop_column('interactions', 'action_type')
alembic/versions/__pycache__/0f355a71adbb_added_interaction_table.cpython-311.pyc ADDED
Binary file (1.74 kB). View file
 
alembic/versions/__pycache__/27fe156a6d72_change_schema_to_unicode.cpython-311.pyc ADDED
Binary file (1.43 kB). View file
 
alembic/versions/__pycache__/3821f7adaca9_add_session_id.cpython-311.pyc ADDED
Binary file (1.15 kB). View file
 
alembic/versions/__pycache__/9ed6d1431c1d_add_platform_and_action_types.cpython-311.pyc ADDED
Binary file (1.43 kB). View file
 
alembic/versions/__pycache__/c3a93ef3de5d_drop_client_id_column.cpython-311.pyc ADDED
Binary file (1.32 kB). View file
 
alembic/versions/__pycache__/ead242c61258_added_user_table.cpython-311.pyc ADDED
Binary file (1.75 kB). View file
 
alembic/versions/__pycache__/eced1ae3918a_add_string_user_id.cpython-311.pyc ADDED
Binary file (1.31 kB). View file
 
alembic/versions/ead242c61258_added_user_table.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Added user table
2
+
3
+ Revision ID: ead242c61258
4
+ Revises:
5
+ Create Date: 2023-06-26 16:25:00.614978
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = 'ead242c61258'
14
+ down_revision = None
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.create_table('users',
21
+ sa.Column('id', sa.Integer(), primary_key=True),
22
+ sa.Column('name', sa.String(), nullable=True),
23
+ sa.Column('email', sa.String(),
24
+ nullable=False, unique=True),
25
+ sa.PrimaryKeyConstraint('id')
26
+ )
27
+ op.create_index(op.f('ix_users_email'), 'users', ['email'], unique=True)
28
+
29
+
30
+ def downgrade() -> None:
31
+ op.drop_index(op.f('ix_users_email'), table_name='users')
32
+ op.drop_table('users')
alembic/versions/eced1ae3918a_add_string_user_id.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Add string user ID
2
+
3
+ Revision ID: eced1ae3918a
4
+ Revises: 3821f7adaca9
5
+ Create Date: 2023-07-19 11:02:52.002939
6
+
7
+ """
8
+ from alembic import op
9
+ import sqlalchemy as sa
10
+
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = 'eced1ae3918a'
14
+ down_revision = '3821f7adaca9'
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ op.add_column('interactions', sa.Column(
21
+ 'user_id', sa.String(50), nullable=True))
22
+
23
+ # Populate the new column with the old column's data
24
+ op.execute("""
25
+ UPDATE interactions
26
+ SET user_id = CAST(client_id AS TEXT)
27
+ """)
28
+
29
+ # TODO: make the user_id column non-nullable after prod migration.
30
+ # Skip for now given production servers are distributed. Note this is not
31
+ # relevant if you deploy locally.
32
+
33
+
34
+ def downgrade() -> None:
35
+ op.drop_column('interactions', 'user_id')
cli.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """A CLI for building an running RealChar project locally."""
3
+ import click
4
+ import os
5
+ import subprocess
6
+
7
+
8
+ @click.group()
9
+ def cli():
10
+ pass
11
+
12
+
13
+ @click.command()
14
+ @click.option('--name', default="realtime-ai-character", help='The name to give to your Docker image.')
15
+ @click.option('--rebuild', is_flag=True, help='Flag to indicate whether to rebuild the Docker image.')
16
+ def docker_build(name, rebuild):
17
+ if rebuild or not image_exists(name):
18
+ click.secho(f"Building Docker image: {name}...", fg='green')
19
+ if (image_exists(name)):
20
+ subprocess.run(["docker", "rmi", "-f", name])
21
+ subprocess.run(["docker", "build", "-t", name, "."])
22
+ else:
23
+ click.secho(
24
+ f"Docker image: {name} already exists. Skipping build. To rebuild, use --rebuild option", fg='yellow')
25
+
26
+
27
+ @click.command()
28
+ @click.option('--name', default="realtime-ai-character", help='The name of the Docker image to run.')
29
+ @click.option('--db-file', default=None, help='Path to the database file to mount inside the container.')
30
+ def docker_run(name, db_file):
31
+ click.secho(f"Running Docker image: {name}...", fg='green')
32
+ if not os.path.isfile('.env'):
33
+ click.secho(
34
+ "Warning: .env file not found. Running without environment variables.", fg='yellow')
35
+ # Remove existing container if it exists
36
+ subprocess.run(["docker", "rm", "-f", name],
37
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
38
+ if db_file:
39
+ subprocess.run(["docker", "run", "--env-file", ".env", "--name", name, "-p", "8000:8000",
40
+ "-v", f"{os.path.abspath(db_file)}:/realtime_ai_character/test.db", name])
41
+ else:
42
+ subprocess.run(["docker", "run", "--env-file", ".env",
43
+ "--name", name, "-p", "8000:8000", name])
44
+
45
+
46
+ @click.command()
47
+ @click.option('--name', default="realtime-ai-character", help='The name of the Docker image to delete.')
48
+ def docker_delete(name):
49
+ if image_exists(name):
50
+ click.secho(f"Deleting Docker image: {name}...", fg='green')
51
+ subprocess.run(["docker", "rmi", "-f", name])
52
+ else:
53
+ click.secho(f"Docker image: {name} does not exist.", fg='yellow')
54
+
55
+
56
+ @click.command(context_settings={"ignore_unknown_options": True})
57
+ @click.argument('args', nargs=-1, type=click.UNPROCESSED)
58
+ def run_uvicorn(args):
59
+ click.secho("Running uvicorn server...", fg='green')
60
+ subprocess.run(["uvicorn", "realtime_ai_character.main:app",
61
+ "--ws-ping-interval", "60", "--ws-ping-timeout", "60", "--timeout-keep-alive", "60"] + list(args))
62
+
63
+
64
+ def image_exists(name):
65
+ result = subprocess.run(
66
+ ["docker", "image", "inspect", name], capture_output=True, text=True)
67
+ return result.returncode == 0
68
+
69
+
70
+ cli.add_command(docker_build)
71
+ cli.add_command(docker_run)
72
+ cli.add_command(docker_delete)
73
+ cli.add_command(run_uvicorn)
74
+
75
+
76
+ if __name__ == '__main__':
77
+ cli()
client/README.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Client
2
+ ---
3
+
4
+ # Mobile
5
+ Read ios/README.md
6
+
7
+ # Web
8
+ Under realtime_ai_character/static
9
+
10
+ # Terminal
11
+ Under client/cli.py
client/cli.py ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import queue
3
+ import asyncio
4
+ import concurrent.futures
5
+ import functools
6
+ import io
7
+ import sys
8
+ import random
9
+ from threading import Thread
10
+ import time
11
+
12
+ from dotenv import load_dotenv
13
+
14
+ import pyaudio
15
+ import speech_recognition as sr
16
+ import websockets
17
+ from aioconsole import ainput # for async input
18
+ from pydub import AudioSegment
19
+ from simpleaudio import WaveObject
20
+
21
+ load_dotenv()
22
+
23
+ executor = concurrent.futures.ThreadPoolExecutor(max_workers=3)
24
+ web2_initial_message = True
25
+
26
+ CHUNK = 1024
27
+ FORMAT = pyaudio.paInt16
28
+ CHANNELS = 1
29
+ RATE = 44100
30
+
31
+
32
+ class AudioPlayer:
33
+ def __init__(self):
34
+ self.play_thread = None
35
+ self.stop_flag = False
36
+ self.queue = queue.Queue()
37
+
38
+ def play_audio(self):
39
+ while not self.stop_flag or not self.queue.empty():
40
+ try:
41
+ wav_data = self.queue.get_nowait()
42
+ except queue.Empty:
43
+ continue
44
+
45
+ wave_obj = WaveObject.from_wave_file(wav_data)
46
+ play_obj = wave_obj.play()
47
+
48
+ while play_obj.is_playing() and not self.stop_flag:
49
+ time.sleep(0.1)
50
+
51
+ if self.stop_flag:
52
+ play_obj.stop()
53
+
54
+ def start_playing(self, wav_data):
55
+ self.stop_flag = False
56
+ self.queue.put(wav_data)
57
+
58
+ if self.play_thread is None or not self.play_thread.is_alive():
59
+ self.play_thread = Thread(target=self.play_audio)
60
+ self.play_thread.start()
61
+
62
+ def stop_playing(self):
63
+ if self.play_thread and self.play_thread.is_alive():
64
+ self.stop_flag = True
65
+ self.play_thread.join()
66
+ self.play_thread = None
67
+
68
+ def add_to_queue(self, wav_data):
69
+ self.queue.put(wav_data)
70
+
71
+
72
+ audio_player = AudioPlayer()
73
+
74
+
75
+ def get_input_device_id():
76
+ p = pyaudio.PyAudio()
77
+ devices = [(i, p.get_device_info_by_index(i)['name'])
78
+ for i in range(p.get_device_count())
79
+ if p.get_device_info_by_index(i).get('maxInputChannels')]
80
+
81
+ print('Available devices:')
82
+ for id, name in devices:
83
+ print(f"Device id {id} - {name}")
84
+
85
+ return int(input('Please select device id: '))
86
+
87
+
88
+ async def handle_audio(websocket, device_id):
89
+ with sr.Microphone(device_index=device_id, sample_rate=RATE) as source:
90
+ recognizer = sr.Recognizer()
91
+ print('Source sample rate: ', source.SAMPLE_RATE)
92
+ print('Source width: ', source.SAMPLE_WIDTH)
93
+ print('Adjusting for ambient noise...Wait for 2 seconds')
94
+ recognizer.energy_threshold = 5000
95
+ recognizer.dynamic_energy_ratio = 6
96
+ recognizer.dynamic_energy_adjustment_damping = 0.85
97
+ recognizer.non_speaking_duration = 0.5
98
+ recognizer.pause_threshold = 0.8
99
+ recognizer.phrase_threshold = 0.5
100
+ recognizer.adjust_for_ambient_noise(source, duration=2)
101
+ listen_func = functools.partial(
102
+ recognizer.listen, source, phrase_time_limit=30)
103
+
104
+ print('Okay, start talking!')
105
+ while True:
106
+ print('[*]', end="") # indicate that we are listening
107
+ audio = await asyncio.get_event_loop().run_in_executor(executor, listen_func)
108
+ await websocket.send(audio.frame_data)
109
+ print('[-]', end="") # indicate that we are done listening
110
+ await asyncio.sleep(2)
111
+
112
+
113
+ async def handle_text(websocket):
114
+ print('You: ', end="", flush=False)
115
+ while True:
116
+ message = await ainput()
117
+ await websocket.send(message)
118
+
119
+ initial_message = True
120
+ async def receive_message(websocket, websocket2):
121
+ web1_init_message = await websocket.recv()
122
+ print('web1_init_message: ', web1_init_message)
123
+
124
+ web2_init_message = await websocket2.recv()
125
+ print('web1_init_message: ', web2_init_message)
126
+ message_to_websocket1 = "Suppose I'm Steve Jobs now. What question do you have for me?"
127
+ await websocket.send(message_to_websocket1)
128
+
129
+ web1_message = ''
130
+ while True:
131
+ try:
132
+ message = await websocket.recv()
133
+ print('here')
134
+ except websockets.exceptions.ConnectionClosedError as e:
135
+ print("Connection closed unexpectedly: ", e)
136
+ break
137
+ except Exception as e:
138
+ print("An error occurred: ", e)
139
+ break
140
+
141
+ if isinstance(message, str):
142
+ if message == '[end]\n':
143
+ if not web1_message:
144
+ continue
145
+ # remove everything before '> ' in the message
146
+ message_to_websocket2 = web1_message[web1_message.find('> ') + 2:]
147
+ # print('message_to_websocket2: ', message_to_websocket2)
148
+ await websocket2.send(message_to_websocket2)
149
+ web2_message = ''
150
+ j = 0
151
+ while True:
152
+ j += 1
153
+ try:
154
+ message = await websocket2.recv()
155
+ except websockets.exceptions.ConnectionClosedError as e:
156
+ print("Connection closed unexpectedly: ", e)
157
+ break
158
+ except Exception as e:
159
+ print("An error occurred: ", e)
160
+ break
161
+
162
+ if isinstance(message, str):
163
+ if message == '[end]\n':
164
+ # print('\nWebsocket2: ', end="", flush=False)
165
+ if not web2_message:
166
+ # print('skip')
167
+ continue
168
+ # remove everything before '> ' in the message
169
+ print(web2_message)
170
+ message_from_websocket2 = web2_message[web2_message.find('> ') + 2:]
171
+ await websocket.send(message_from_websocket2)
172
+ break
173
+ elif message.startswith('[+]'):
174
+ # stop playing audio
175
+ audio_player.stop_playing()
176
+ # indicate the transcription is done
177
+ # print(f"\nnWebsocket2: {message}", end="\n", flush=False)
178
+ elif message.startswith('[=]'):
179
+ # indicate the response is done
180
+ # print(f"nWebsocket2: {web2_message}", end="\n", flush=False)
181
+ pass
182
+ else:
183
+ # print('\nmessage++\n')
184
+ web2_message += message
185
+ elif isinstance(message, bytes):
186
+ global web2_initial_message
187
+ if web2_initial_message:
188
+ web2_initial_message = False
189
+ continue
190
+ audio_data = io.BytesIO(message)
191
+ audio = AudioSegment.from_mp3(audio_data)
192
+ wav_data = io.BytesIO()
193
+ audio.export(wav_data, format="wav")
194
+ # Start playing audio
195
+ audio_player.start_playing(wav_data)
196
+
197
+ elif message.startswith('[+]'):
198
+ # stop playing audio
199
+ audio_player.stop_playing()
200
+ # indicate the transcription is done
201
+ print(f"\n{message}", end="\n", flush=False)
202
+ elif message.startswith('[=]'):
203
+ # indicate the response is done
204
+ print(f"{message}", end="\n", flush=False)
205
+ else:
206
+ web1_message += message
207
+ print(f"{message}", end="", flush=False)
208
+ elif isinstance(message, bytes):
209
+ audio_data = io.BytesIO(message)
210
+ audio = AudioSegment.from_mp3(audio_data)
211
+ wav_data = io.BytesIO()
212
+ audio.export(wav_data, format="wav")
213
+ # Start playing audio
214
+ audio_player.start_playing(wav_data)
215
+ else:
216
+ print("Unexpected message")
217
+ break
218
+
219
+
220
+ def select_model():
221
+ llm_model_selection = input(
222
+ '1: gpt-3.5-turbo-16k \n'
223
+ '2: gpt-4 \n'
224
+ '3: claude-2 \n'
225
+ 'Select llm model:')
226
+ if llm_model_selection == '1':
227
+ llm_model = 'gpt-3.5-turbo-16k'
228
+ elif llm_model_selection == '2':
229
+ llm_model = 'gpt-4'
230
+ elif llm_model_selection == '3':
231
+ llm_model = 'claude-2'
232
+ return llm_model
233
+
234
+
235
+ async def start_client(client_id, url):
236
+ api_key = os.getenv('AUTH_API_KEY')
237
+ llm_model = select_model()
238
+ uri = f"ws://{url}/ws/{client_id}?api_key={api_key}&llm_model={llm_model}"
239
+ async with websockets.connect(uri) as websocket:
240
+ uri2 = f"ws://{url}/ws/9999999?api_key={api_key}&llm_model={llm_model}"
241
+ # send client platform info
242
+ async with websockets.connect(uri2) as websocket2:
243
+ await websocket.send('terminal')
244
+ await websocket2.send('terminal')
245
+ print(f"Client #{client_id} connected to websocket1")
246
+ print(f"Client 9999999 connected to websocket2")
247
+ welcome_message = await websocket.recv()
248
+ welcome_message2 = await websocket2.recv()
249
+ print(f"{welcome_message}")
250
+ character = input('Select character: ')
251
+ await websocket.send(character)
252
+ await websocket2.send('6')
253
+
254
+ mode = input('Select mode (1: audio, 2: text): ')
255
+ if mode.lower() == '1':
256
+ device_id = get_input_device_id()
257
+ send_task = asyncio.create_task(handle_audio(websocket, device_id))
258
+ else:
259
+ send_task = asyncio.create_task(handle_text(websocket))
260
+
261
+ receive_task = asyncio.create_task(receive_message(websocket, websocket2))
262
+ await asyncio.gather(receive_task, send_task)
263
+
264
+
265
+ async def main(url):
266
+ client_id = random.randint(0, 1000000)
267
+ task = asyncio.create_task(start_client(client_id, url))
268
+ try:
269
+ await task
270
+ except KeyboardInterrupt:
271
+ task.cancel()
272
+ await asyncio.wait_for(task, timeout=None)
273
+ print("Client stopped by user")
274
+
275
+
276
+ if __name__ == "__main__":
277
+ url = sys.argv[1] if len(sys.argv) > 1 else 'localhost:8000'
278
+ asyncio.run(main(url))
client/mobile/ios/.gitignore ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Git ignore for iOS app on Mac OS
2
+ # Created by https://www.toptal.com/developers/gitignore/api/xcode,osx,swift,objective-c,cocoapods
3
+ # Edit at https://www.toptal.com/developers/gitignore?templates=xcode,osx,swift,objective-c,cocoapods
4
+
5
+ ### CocoaPods ###
6
+ ## CocoaPods GitIgnore Template
7
+
8
+ # CocoaPods - Only use to conserve bandwidth / Save time on Pushing
9
+ # - Also handy if you have a large number of dependant pods
10
+ # - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE
11
+ Pods/
12
+
13
+ ### Objective-C ###
14
+ # Xcode
15
+ #
16
+ # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
17
+
18
+ ## User settings
19
+ xcuserdata/
20
+
21
+ ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
22
+ *.xcscmblueprint
23
+ *.xccheckout
24
+
25
+ ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
26
+ build/
27
+ DerivedData/
28
+ *.moved-aside
29
+ *.pbxuser
30
+ !default.pbxuser
31
+ *.mode1v3
32
+ !default.mode1v3
33
+ *.mode2v3
34
+ !default.mode2v3
35
+ *.perspectivev3
36
+ !default.perspectivev3
37
+
38
+ ## Obj-C/Swift specific
39
+ *.hmap
40
+
41
+ ## App packaging
42
+ *.ipa
43
+ *.dSYM.zip
44
+ *.dSYM
45
+
46
+ # CocoaPods
47
+ # We recommend against adding the Pods directory to your .gitignore. However
48
+ # you should judge for yourself, the pros and cons are mentioned at:
49
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
50
+ # Pods/
51
+ # Add this line if you want to avoid checking in source code from the Xcode workspace
52
+ # *.xcworkspace
53
+
54
+ # Carthage
55
+ # Add this line if you want to avoid checking in source code from Carthage dependencies.
56
+ # Carthage/Checkouts
57
+
58
+ Carthage/Build/
59
+
60
+ # fastlane
61
+ # It is recommended to not store the screenshots in the git repo.
62
+ # Instead, use fastlane to re-generate the screenshots whenever they are needed.
63
+ # For more information about the recommended setup visit:
64
+ # https://docs.fastlane.tools/best-practices/source-control/#source-control
65
+
66
+ fastlane/report.xml
67
+ fastlane/Preview.html
68
+ fastlane/screenshots/**/*.png
69
+ fastlane/test_output
70
+
71
+ # Code Injection
72
+ # After new code Injection tools there's a generated folder /iOSInjectionProject
73
+ # https://github.com/johnno1962/injectionforxcode
74
+
75
+ iOSInjectionProject/
76
+
77
+ ### Objective-C Patch ###
78
+
79
+ ### OSX ###
80
+ # General
81
+ .DS_Store
82
+ .AppleDouble
83
+ .LSOverride
84
+
85
+ # Icon must end with two \r
86
+ Icon
87
+
88
+
89
+ # Thumbnails
90
+ ._*
91
+
92
+ # Files that might appear in the root of a volume
93
+ .DocumentRevisions-V100
94
+ .fseventsd
95
+ .Spotlight-V100
96
+ .TemporaryItems
97
+ .Trashes
98
+ .VolumeIcon.icns
99
+ .com.apple.timemachine.donotpresent
100
+
101
+ # Directories potentially created on remote AFP share
102
+ .AppleDB
103
+ .AppleDesktop
104
+ Network Trash Folder
105
+ Temporary Items
106
+ .apdisk
107
+
108
+ ### Swift ###
109
+ # Xcode
110
+ # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
111
+
112
+
113
+
114
+
115
+
116
+
117
+ ## Playgrounds
118
+ timeline.xctimeline
119
+ playground.xcworkspace
120
+
121
+ # Swift Package Manager
122
+ # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
123
+ # Packages/
124
+ # Package.pins
125
+ # Package.resolved
126
+ # *.xcodeproj
127
+ # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
128
+ # hence it is not needed unless you have added a package configuration file to your project
129
+ # .swiftpm
130
+
131
+ .build/
132
+
133
+ # CocoaPods
134
+ # We recommend against adding the Pods directory to your .gitignore. However
135
+ # you should judge for yourself, the pros and cons are mentioned at:
136
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
137
+ # Pods/
138
+ # Add this line if you want to avoid checking in source code from the Xcode workspace
139
+ # *.xcworkspace
140
+
141
+ # Carthage
142
+ # Add this line if you want to avoid checking in source code from Carthage dependencies.
143
+ # Carthage/Checkouts
144
+
145
+
146
+ # Accio dependency management
147
+ Dependencies/
148
+ .accio/
149
+
150
+ # fastlane
151
+ # It is recommended to not store the screenshots in the git repo.
152
+ # Instead, use fastlane to re-generate the screenshots whenever they are needed.
153
+ # For more information about the recommended setup visit:
154
+ # https://docs.fastlane.tools/best-practices/source-control/#source-control
155
+
156
+
157
+ # Code Injection
158
+ # After new code Injection tools there's a generated folder /iOSInjectionProject
159
+ # https://github.com/johnno1962/injectionforxcode
160
+
161
+
162
+ ### Xcode ###
163
+
164
+ ## Xcode 8 and earlier
165
+
166
+ ### Xcode Patch ###
167
+ *.xcodeproj/*
168
+ !*.xcodeproj/project.pbxproj
169
+ !*.xcodeproj/xcshareddata/
170
+ !*.xcodeproj/project.xcworkspace/
171
+ !*.xcworkspace/contents.xcworkspacedata
172
+ /*.gcno
173
+ **/xcshareddata/WorkspaceSettings.xcsettings
174
+
175
+ # End of https://www.toptal.com/developers/gitignore/api/xcode,osx,swift,objective-c,cocoapods
client/mobile/ios/rac/rac.xcodeproj/project.pbxproj ADDED
@@ -0,0 +1,597 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // !$*UTF8*$!
2
+ {
3
+ archiveVersion = 1;
4
+ classes = {
5
+ };
6
+ objectVersion = 56;
7
+ objects = {
8
+
9
+ /* Begin PBXBuildFile section */
10
+ 2600B06F2A5D0872003E8388 /* ChatMessagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2600B06E2A5D0872003E8388 /* ChatMessagesView.swift */; };
11
+ 2600B0712A5D11DD003E8388 /* VoiceMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2600B0702A5D11DD003E8388 /* VoiceMessageView.swift */; };
12
+ 2600B0732A60985F003E8388 /* SpeechRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2600B0722A60985F003E8388 /* SpeechRecognizer.swift */; };
13
+ 2600B0762A60A024003E8388 /* WebSocketClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2600B0752A60A024003E8388 /* WebSocketClient.swift */; };
14
+ 2600B0782A60C6CE003E8388 /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2600B0772A60C6CE003E8388 /* AudioPlayer.swift */; };
15
+ 2600B07B2A61EA86003E8388 /* CachedAsyncImage in Frameworks */ = {isa = PBXBuildFile; productRef = 2600B07A2A61EA86003E8388 /* CachedAsyncImage */; };
16
+ 2600B07E2A68D641003E8388 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2600B07D2A68D641003E8388 /* SettingsView.swift */; };
17
+ 2600B0802A68F517003E8388 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2600B07F2A68F517003E8388 /* GoogleService-Info.plist */; };
18
+ 2600B0832A68F585003E8388 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 2600B0822A68F585003E8388 /* FirebaseAnalytics */; };
19
+ 2600B0852A68F585003E8388 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 2600B0842A68F585003E8388 /* FirebaseAuth */; };
20
+ 2600B0872A68F585003E8388 /* FirebaseAuthCombine-Community in Frameworks */ = {isa = PBXBuildFile; productRef = 2600B0862A68F585003E8388 /* FirebaseAuthCombine-Community */; };
21
+ 2600B08C2A68FC8C003E8388 /* GoogleSignInSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 2600B08B2A68FC8C003E8388 /* GoogleSignInSwift */; };
22
+ 2600B08E2A68FCA9003E8388 /* GoogleSignInButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2600B08D2A68FCA9003E8388 /* GoogleSignInButton.swift */; };
23
+ 2600B0902A69DCC7003E8388 /* UserSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2600B08F2A69DCC7003E8388 /* UserSettings.swift */; };
24
+ 2600B0922A69F786003E8388 /* PreferenceSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2600B0912A69F786003E8388 /* PreferenceSettings.swift */; };
25
+ 26FE4D092A5B6F0D006A1882 /* racApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26FE4D082A5B6F0D006A1882 /* racApp.swift */; };
26
+ 26FE4D0B2A5B6F0D006A1882 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26FE4D0A2A5B6F0D006A1882 /* RootView.swift */; };
27
+ 26FE4D0D2A5B6F0E006A1882 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 26FE4D0C2A5B6F0E006A1882 /* Assets.xcassets */; };
28
+ 26FE4D102A5B6F0E006A1882 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 26FE4D0F2A5B6F0E006A1882 /* Preview Assets.xcassets */; };
29
+ 26FE4D1D2A5B7009006A1882 /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26FE4D1C2A5B7009006A1882 /* WelcomeView.swift */; };
30
+ 26FE4D1F2A5B704C006A1882 /* InteractiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26FE4D1E2A5B704C006A1882 /* InteractiveView.swift */; };
31
+ 26FE4D212A5B7074006A1882 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26FE4D202A5B7074006A1882 /* AboutView.swift */; };
32
+ 26FE4D232A5B707B006A1882 /* ConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26FE4D222A5B707B006A1882 /* ConfigView.swift */; };
33
+ 26FE4D272A5BBFD7006A1882 /* Prompt-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 26FE4D252A5BBFD7006A1882 /* Prompt-SemiBold.ttf */; };
34
+ 26FE4D282A5BBFD7006A1882 /* Prompt-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 26FE4D262A5BBFD7006A1882 /* Prompt-Regular.ttf */; };
35
+ 26FE4D2C2A5BC25C006A1882 /* CtaButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26FE4D2B2A5BC25C006A1882 /* CtaButton.swift */; };
36
+ 26FE4D2E2A5BC3D2006A1882 /* Prompt-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 26FE4D2D2A5BC3D2006A1882 /* Prompt-Medium.ttf */; };
37
+ 26FE4D312A5BC6B0006A1882 /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26FE4D302A5BC6B0006A1882 /* View+Extensions.swift */; };
38
+ /* End PBXBuildFile section */
39
+
40
+ /* Begin PBXFileReference section */
41
+ 2600B06E2A5D0872003E8388 /* ChatMessagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMessagesView.swift; sourceTree = "<group>"; };
42
+ 2600B0702A5D11DD003E8388 /* VoiceMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceMessageView.swift; sourceTree = "<group>"; };
43
+ 2600B0722A60985F003E8388 /* SpeechRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpeechRecognizer.swift; sourceTree = "<group>"; };
44
+ 2600B0752A60A024003E8388 /* WebSocketClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSocketClient.swift; sourceTree = "<group>"; };
45
+ 2600B0772A60C6CE003E8388 /* AudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = "<group>"; };
46
+ 2600B07D2A68D641003E8388 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
47
+ 2600B07F2A68F517003E8388 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
48
+ 2600B08D2A68FCA9003E8388 /* GoogleSignInButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleSignInButton.swift; sourceTree = "<group>"; };
49
+ 2600B08F2A69DCC7003E8388 /* UserSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettings.swift; sourceTree = "<group>"; };
50
+ 2600B0912A69F786003E8388 /* PreferenceSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceSettings.swift; sourceTree = "<group>"; };
51
+ 26FE4D052A5B6F0D006A1882 /* rac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = rac.app; sourceTree = BUILT_PRODUCTS_DIR; };
52
+ 26FE4D082A5B6F0D006A1882 /* racApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = racApp.swift; sourceTree = "<group>"; };
53
+ 26FE4D0A2A5B6F0D006A1882 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = "<group>"; };
54
+ 26FE4D0C2A5B6F0E006A1882 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
55
+ 26FE4D0F2A5B6F0E006A1882 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
56
+ 26FE4D1C2A5B7009006A1882 /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = "<group>"; };
57
+ 26FE4D1E2A5B704C006A1882 /* InteractiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InteractiveView.swift; sourceTree = "<group>"; };
58
+ 26FE4D202A5B7074006A1882 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
59
+ 26FE4D222A5B707B006A1882 /* ConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigView.swift; sourceTree = "<group>"; };
60
+ 26FE4D252A5BBFD7006A1882 /* Prompt-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Prompt-SemiBold.ttf"; sourceTree = "<group>"; };
61
+ 26FE4D262A5BBFD7006A1882 /* Prompt-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Prompt-Regular.ttf"; sourceTree = "<group>"; };
62
+ 26FE4D292A5BC094006A1882 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
63
+ 26FE4D2B2A5BC25C006A1882 /* CtaButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CtaButton.swift; sourceTree = "<group>"; };
64
+ 26FE4D2D2A5BC3D2006A1882 /* Prompt-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Prompt-Medium.ttf"; sourceTree = "<group>"; };
65
+ 26FE4D302A5BC6B0006A1882 /* View+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; };
66
+ /* End PBXFileReference section */
67
+
68
+ /* Begin PBXFrameworksBuildPhase section */
69
+ 26FE4D022A5B6F0D006A1882 /* Frameworks */ = {
70
+ isa = PBXFrameworksBuildPhase;
71
+ buildActionMask = 2147483647;
72
+ files = (
73
+ 2600B08C2A68FC8C003E8388 /* GoogleSignInSwift in Frameworks */,
74
+ 2600B0832A68F585003E8388 /* FirebaseAnalytics in Frameworks */,
75
+ 2600B0852A68F585003E8388 /* FirebaseAuth in Frameworks */,
76
+ 2600B07B2A61EA86003E8388 /* CachedAsyncImage in Frameworks */,
77
+ 2600B0872A68F585003E8388 /* FirebaseAuthCombine-Community in Frameworks */,
78
+ );
79
+ runOnlyForDeploymentPostprocessing = 0;
80
+ };
81
+ /* End PBXFrameworksBuildPhase section */
82
+
83
+ /* Begin PBXGroup section */
84
+ 2600B0742A60A014003E8388 /* Network */ = {
85
+ isa = PBXGroup;
86
+ children = (
87
+ 2600B0752A60A024003E8388 /* WebSocketClient.swift */,
88
+ );
89
+ path = Network;
90
+ sourceTree = "<group>";
91
+ };
92
+ 2600B07C2A68D633003E8388 /* Settings */ = {
93
+ isa = PBXGroup;
94
+ children = (
95
+ 2600B07D2A68D641003E8388 /* SettingsView.swift */,
96
+ 2600B08D2A68FCA9003E8388 /* GoogleSignInButton.swift */,
97
+ 2600B08F2A69DCC7003E8388 /* UserSettings.swift */,
98
+ 2600B0912A69F786003E8388 /* PreferenceSettings.swift */,
99
+ );
100
+ path = Settings;
101
+ sourceTree = "<group>";
102
+ };
103
+ 26FE4CFC2A5B6F0D006A1882 = {
104
+ isa = PBXGroup;
105
+ children = (
106
+ 26FE4D072A5B6F0D006A1882 /* rac */,
107
+ 26FE4D062A5B6F0D006A1882 /* Products */,
108
+ );
109
+ sourceTree = "<group>";
110
+ };
111
+ 26FE4D062A5B6F0D006A1882 /* Products */ = {
112
+ isa = PBXGroup;
113
+ children = (
114
+ 26FE4D052A5B6F0D006A1882 /* rac.app */,
115
+ );
116
+ name = Products;
117
+ sourceTree = "<group>";
118
+ };
119
+ 26FE4D072A5B6F0D006A1882 /* rac */ = {
120
+ isa = PBXGroup;
121
+ children = (
122
+ 26FE4D292A5BC094006A1882 /* Info.plist */,
123
+ 2600B07F2A68F517003E8388 /* GoogleService-Info.plist */,
124
+ 26FE4D082A5B6F0D006A1882 /* racApp.swift */,
125
+ 26FE4D0A2A5B6F0D006A1882 /* RootView.swift */,
126
+ 26FE4D192A5B6FBD006A1882 /* Interactive */,
127
+ 26FE4D162A5B6F89006A1882 /* Welcome */,
128
+ 26FE4D2A2A5BC1D5006A1882 /* SharedUI */,
129
+ 26FE4D2F2A5BC6A4006A1882 /* Extension */,
130
+ 2600B0742A60A014003E8388 /* Network */,
131
+ 26FE4D242A5BBF94006A1882 /* Assets */,
132
+ 26FE4D0E2A5B6F0E006A1882 /* Preview Content */,
133
+ );
134
+ path = rac;
135
+ sourceTree = "<group>";
136
+ };
137
+ 26FE4D0E2A5B6F0E006A1882 /* Preview Content */ = {
138
+ isa = PBXGroup;
139
+ children = (
140
+ 26FE4D0F2A5B6F0E006A1882 /* Preview Assets.xcassets */,
141
+ );
142
+ path = "Preview Content";
143
+ sourceTree = "<group>";
144
+ };
145
+ 26FE4D162A5B6F89006A1882 /* Welcome */ = {
146
+ isa = PBXGroup;
147
+ children = (
148
+ 26FE4D172A5B6FA4006A1882 /* About */,
149
+ 26FE4D182A5B6FAA006A1882 /* Config */,
150
+ 2600B07C2A68D633003E8388 /* Settings */,
151
+ 26FE4D1C2A5B7009006A1882 /* WelcomeView.swift */,
152
+ );
153
+ path = Welcome;
154
+ sourceTree = "<group>";
155
+ };
156
+ 26FE4D172A5B6FA4006A1882 /* About */ = {
157
+ isa = PBXGroup;
158
+ children = (
159
+ 26FE4D202A5B7074006A1882 /* AboutView.swift */,
160
+ );
161
+ path = About;
162
+ sourceTree = "<group>";
163
+ };
164
+ 26FE4D182A5B6FAA006A1882 /* Config */ = {
165
+ isa = PBXGroup;
166
+ children = (
167
+ 26FE4D222A5B707B006A1882 /* ConfigView.swift */,
168
+ );
169
+ path = Config;
170
+ sourceTree = "<group>";
171
+ };
172
+ 26FE4D192A5B6FBD006A1882 /* Interactive */ = {
173
+ isa = PBXGroup;
174
+ children = (
175
+ 26FE4D1B2A5B6FCE006A1882 /* Text */,
176
+ 26FE4D1A2A5B6FC4006A1882 /* Voice */,
177
+ 26FE4D1E2A5B704C006A1882 /* InteractiveView.swift */,
178
+ );
179
+ path = Interactive;
180
+ sourceTree = "<group>";
181
+ };
182
+ 26FE4D1A2A5B6FC4006A1882 /* Voice */ = {
183
+ isa = PBXGroup;
184
+ children = (
185
+ 2600B0702A5D11DD003E8388 /* VoiceMessageView.swift */,
186
+ 2600B0722A60985F003E8388 /* SpeechRecognizer.swift */,
187
+ 2600B0772A60C6CE003E8388 /* AudioPlayer.swift */,
188
+ );
189
+ path = Voice;
190
+ sourceTree = "<group>";
191
+ };
192
+ 26FE4D1B2A5B6FCE006A1882 /* Text */ = {
193
+ isa = PBXGroup;
194
+ children = (
195
+ 2600B06E2A5D0872003E8388 /* ChatMessagesView.swift */,
196
+ );
197
+ path = Text;
198
+ sourceTree = "<group>";
199
+ };
200
+ 26FE4D242A5BBF94006A1882 /* Assets */ = {
201
+ isa = PBXGroup;
202
+ children = (
203
+ 26FE4D262A5BBFD7006A1882 /* Prompt-Regular.ttf */,
204
+ 26FE4D2D2A5BC3D2006A1882 /* Prompt-Medium.ttf */,
205
+ 26FE4D252A5BBFD7006A1882 /* Prompt-SemiBold.ttf */,
206
+ 26FE4D0C2A5B6F0E006A1882 /* Assets.xcassets */,
207
+ );
208
+ path = Assets;
209
+ sourceTree = "<group>";
210
+ };
211
+ 26FE4D2A2A5BC1D5006A1882 /* SharedUI */ = {
212
+ isa = PBXGroup;
213
+ children = (
214
+ 26FE4D2B2A5BC25C006A1882 /* CtaButton.swift */,
215
+ );
216
+ path = SharedUI;
217
+ sourceTree = "<group>";
218
+ };
219
+ 26FE4D2F2A5BC6A4006A1882 /* Extension */ = {
220
+ isa = PBXGroup;
221
+ children = (
222
+ 26FE4D302A5BC6B0006A1882 /* View+Extensions.swift */,
223
+ );
224
+ path = Extension;
225
+ sourceTree = "<group>";
226
+ };
227
+ /* End PBXGroup section */
228
+
229
+ /* Begin PBXNativeTarget section */
230
+ 26FE4D042A5B6F0D006A1882 /* rac */ = {
231
+ isa = PBXNativeTarget;
232
+ buildConfigurationList = 26FE4D132A5B6F0E006A1882 /* Build configuration list for PBXNativeTarget "rac" */;
233
+ buildPhases = (
234
+ 26FE4D012A5B6F0D006A1882 /* Sources */,
235
+ 26FE4D022A5B6F0D006A1882 /* Frameworks */,
236
+ 26FE4D032A5B6F0D006A1882 /* Resources */,
237
+ );
238
+ buildRules = (
239
+ );
240
+ dependencies = (
241
+ );
242
+ name = rac;
243
+ packageProductDependencies = (
244
+ 2600B07A2A61EA86003E8388 /* CachedAsyncImage */,
245
+ 2600B0822A68F585003E8388 /* FirebaseAnalytics */,
246
+ 2600B0842A68F585003E8388 /* FirebaseAuth */,
247
+ 2600B0862A68F585003E8388 /* FirebaseAuthCombine-Community */,
248
+ 2600B08B2A68FC8C003E8388 /* GoogleSignInSwift */,
249
+ );
250
+ productName = rac;
251
+ productReference = 26FE4D052A5B6F0D006A1882 /* rac.app */;
252
+ productType = "com.apple.product-type.application";
253
+ };
254
+ /* End PBXNativeTarget section */
255
+
256
+ /* Begin PBXProject section */
257
+ 26FE4CFD2A5B6F0D006A1882 /* Project object */ = {
258
+ isa = PBXProject;
259
+ attributes = {
260
+ BuildIndependentTargetsInParallel = 1;
261
+ LastSwiftUpdateCheck = 1430;
262
+ LastUpgradeCheck = 1430;
263
+ TargetAttributes = {
264
+ 26FE4D042A5B6F0D006A1882 = {
265
+ CreatedOnToolsVersion = 14.3.1;
266
+ };
267
+ };
268
+ };
269
+ buildConfigurationList = 26FE4D002A5B6F0D006A1882 /* Build configuration list for PBXProject "rac" */;
270
+ compatibilityVersion = "Xcode 14.0";
271
+ developmentRegion = en;
272
+ hasScannedForEncodings = 0;
273
+ knownRegions = (
274
+ en,
275
+ Base,
276
+ );
277
+ mainGroup = 26FE4CFC2A5B6F0D006A1882;
278
+ packageReferences = (
279
+ 2600B0792A61EA86003E8388 /* XCRemoteSwiftPackageReference "swiftui-cached-async-image" */,
280
+ 2600B0812A68F585003E8388 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
281
+ 2600B08A2A68FC8C003E8388 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */,
282
+ );
283
+ productRefGroup = 26FE4D062A5B6F0D006A1882 /* Products */;
284
+ projectDirPath = "";
285
+ projectRoot = "";
286
+ targets = (
287
+ 26FE4D042A5B6F0D006A1882 /* rac */,
288
+ );
289
+ };
290
+ /* End PBXProject section */
291
+
292
+ /* Begin PBXResourcesBuildPhase section */
293
+ 26FE4D032A5B6F0D006A1882 /* Resources */ = {
294
+ isa = PBXResourcesBuildPhase;
295
+ buildActionMask = 2147483647;
296
+ files = (
297
+ 26FE4D272A5BBFD7006A1882 /* Prompt-SemiBold.ttf in Resources */,
298
+ 26FE4D102A5B6F0E006A1882 /* Preview Assets.xcassets in Resources */,
299
+ 26FE4D0D2A5B6F0E006A1882 /* Assets.xcassets in Resources */,
300
+ 26FE4D2E2A5BC3D2006A1882 /* Prompt-Medium.ttf in Resources */,
301
+ 26FE4D282A5BBFD7006A1882 /* Prompt-Regular.ttf in Resources */,
302
+ 2600B0802A68F517003E8388 /* GoogleService-Info.plist in Resources */,
303
+ );
304
+ runOnlyForDeploymentPostprocessing = 0;
305
+ };
306
+ /* End PBXResourcesBuildPhase section */
307
+
308
+ /* Begin PBXSourcesBuildPhase section */
309
+ 26FE4D012A5B6F0D006A1882 /* Sources */ = {
310
+ isa = PBXSourcesBuildPhase;
311
+ buildActionMask = 2147483647;
312
+ files = (
313
+ 26FE4D232A5B707B006A1882 /* ConfigView.swift in Sources */,
314
+ 2600B0922A69F786003E8388 /* PreferenceSettings.swift in Sources */,
315
+ 26FE4D0B2A5B6F0D006A1882 /* RootView.swift in Sources */,
316
+ 2600B0762A60A024003E8388 /* WebSocketClient.swift in Sources */,
317
+ 2600B0732A60985F003E8388 /* SpeechRecognizer.swift in Sources */,
318
+ 2600B08E2A68FCA9003E8388 /* GoogleSignInButton.swift in Sources */,
319
+ 26FE4D1F2A5B704C006A1882 /* InteractiveView.swift in Sources */,
320
+ 26FE4D2C2A5BC25C006A1882 /* CtaButton.swift in Sources */,
321
+ 2600B06F2A5D0872003E8388 /* ChatMessagesView.swift in Sources */,
322
+ 2600B07E2A68D641003E8388 /* SettingsView.swift in Sources */,
323
+ 26FE4D1D2A5B7009006A1882 /* WelcomeView.swift in Sources */,
324
+ 26FE4D092A5B6F0D006A1882 /* racApp.swift in Sources */,
325
+ 2600B0712A5D11DD003E8388 /* VoiceMessageView.swift in Sources */,
326
+ 26FE4D312A5BC6B0006A1882 /* View+Extensions.swift in Sources */,
327
+ 2600B0902A69DCC7003E8388 /* UserSettings.swift in Sources */,
328
+ 2600B0782A60C6CE003E8388 /* AudioPlayer.swift in Sources */,
329
+ 26FE4D212A5B7074006A1882 /* AboutView.swift in Sources */,
330
+ );
331
+ runOnlyForDeploymentPostprocessing = 0;
332
+ };
333
+ /* End PBXSourcesBuildPhase section */
334
+
335
+ /* Begin XCBuildConfiguration section */
336
+ 26FE4D112A5B6F0E006A1882 /* Debug */ = {
337
+ isa = XCBuildConfiguration;
338
+ buildSettings = {
339
+ ALWAYS_SEARCH_USER_PATHS = NO;
340
+ CLANG_ANALYZER_NONNULL = YES;
341
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
342
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
343
+ CLANG_ENABLE_MODULES = YES;
344
+ CLANG_ENABLE_OBJC_ARC = YES;
345
+ CLANG_ENABLE_OBJC_WEAK = YES;
346
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
347
+ CLANG_WARN_BOOL_CONVERSION = YES;
348
+ CLANG_WARN_COMMA = YES;
349
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
350
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
351
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
352
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
353
+ CLANG_WARN_EMPTY_BODY = YES;
354
+ CLANG_WARN_ENUM_CONVERSION = YES;
355
+ CLANG_WARN_INFINITE_RECURSION = YES;
356
+ CLANG_WARN_INT_CONVERSION = YES;
357
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
358
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
359
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
360
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
361
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
362
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
363
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
364
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
365
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
366
+ CLANG_WARN_UNREACHABLE_CODE = YES;
367
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
368
+ COPY_PHASE_STRIP = NO;
369
+ DEBUG_INFORMATION_FORMAT = dwarf;
370
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
371
+ ENABLE_TESTABILITY = YES;
372
+ GCC_C_LANGUAGE_STANDARD = gnu11;
373
+ GCC_DYNAMIC_NO_PIC = NO;
374
+ GCC_NO_COMMON_BLOCKS = YES;
375
+ GCC_OPTIMIZATION_LEVEL = 0;
376
+ GCC_PREPROCESSOR_DEFINITIONS = (
377
+ "DEBUG=1",
378
+ "$(inherited)",
379
+ );
380
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
381
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
382
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
383
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
384
+ GCC_WARN_UNUSED_FUNCTION = YES;
385
+ GCC_WARN_UNUSED_VARIABLE = YES;
386
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
387
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
388
+ MTL_FAST_MATH = YES;
389
+ ONLY_ACTIVE_ARCH = YES;
390
+ SDKROOT = iphoneos;
391
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
392
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
393
+ };
394
+ name = Debug;
395
+ };
396
+ 26FE4D122A5B6F0E006A1882 /* Release */ = {
397
+ isa = XCBuildConfiguration;
398
+ buildSettings = {
399
+ ALWAYS_SEARCH_USER_PATHS = NO;
400
+ CLANG_ANALYZER_NONNULL = YES;
401
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
402
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
403
+ CLANG_ENABLE_MODULES = YES;
404
+ CLANG_ENABLE_OBJC_ARC = YES;
405
+ CLANG_ENABLE_OBJC_WEAK = YES;
406
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
407
+ CLANG_WARN_BOOL_CONVERSION = YES;
408
+ CLANG_WARN_COMMA = YES;
409
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
410
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
411
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
412
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
413
+ CLANG_WARN_EMPTY_BODY = YES;
414
+ CLANG_WARN_ENUM_CONVERSION = YES;
415
+ CLANG_WARN_INFINITE_RECURSION = YES;
416
+ CLANG_WARN_INT_CONVERSION = YES;
417
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
418
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
419
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
420
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
421
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
422
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
423
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
424
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
425
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
426
+ CLANG_WARN_UNREACHABLE_CODE = YES;
427
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
428
+ COPY_PHASE_STRIP = NO;
429
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
430
+ ENABLE_NS_ASSERTIONS = NO;
431
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
432
+ GCC_C_LANGUAGE_STANDARD = gnu11;
433
+ GCC_NO_COMMON_BLOCKS = YES;
434
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
435
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
436
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
437
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
438
+ GCC_WARN_UNUSED_FUNCTION = YES;
439
+ GCC_WARN_UNUSED_VARIABLE = YES;
440
+ IPHONEOS_DEPLOYMENT_TARGET = 16.4;
441
+ MTL_ENABLE_DEBUG_INFO = NO;
442
+ MTL_FAST_MATH = YES;
443
+ SDKROOT = iphoneos;
444
+ SWIFT_COMPILATION_MODE = wholemodule;
445
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
446
+ VALIDATE_PRODUCT = YES;
447
+ };
448
+ name = Release;
449
+ };
450
+ 26FE4D142A5B6F0E006A1882 /* Debug */ = {
451
+ isa = XCBuildConfiguration;
452
+ buildSettings = {
453
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
454
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
455
+ CODE_SIGN_STYLE = Automatic;
456
+ CURRENT_PROJECT_VERSION = 202307151549;
457
+ DEVELOPMENT_ASSET_PATHS = "\"rac/Preview Content\"";
458
+ DEVELOPMENT_TEAM = T4PLTPSZ3V;
459
+ ENABLE_PREVIEWS = YES;
460
+ GENERATE_INFOPLIST_FILE = YES;
461
+ INFOPLIST_FILE = rac/Info.plist;
462
+ INFOPLIST_KEY_CFBundleDisplayName = RealChar;
463
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment";
464
+ INFOPLIST_KEY_NSMicrophoneUsageDescription = "You can send voice message to your favorite realtime AI chacater.";
465
+ INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "You can send voice message to your favorite realtime AI chacater.";
466
+ INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
467
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
468
+ INFOPLIST_KEY_UILaunchScreen_Generation = YES;
469
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
470
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
471
+ LD_RUNPATH_SEARCH_PATHS = (
472
+ "$(inherited)",
473
+ "@executable_path/Frameworks",
474
+ );
475
+ MARKETING_VERSION = 0.1;
476
+ PRODUCT_BUNDLE_IDENTIFIER = ai.realchar.app;
477
+ PRODUCT_NAME = "$(TARGET_NAME)";
478
+ SWIFT_EMIT_LOC_STRINGS = YES;
479
+ SWIFT_VERSION = 5.0;
480
+ TARGETED_DEVICE_FAMILY = "1,2";
481
+ };
482
+ name = Debug;
483
+ };
484
+ 26FE4D152A5B6F0E006A1882 /* Release */ = {
485
+ isa = XCBuildConfiguration;
486
+ buildSettings = {
487
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
488
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
489
+ CODE_SIGN_STYLE = Automatic;
490
+ CURRENT_PROJECT_VERSION = 202307151549;
491
+ DEVELOPMENT_ASSET_PATHS = "\"rac/Preview Content\"";
492
+ DEVELOPMENT_TEAM = T4PLTPSZ3V;
493
+ ENABLE_PREVIEWS = YES;
494
+ GENERATE_INFOPLIST_FILE = YES;
495
+ INFOPLIST_FILE = rac/Info.plist;
496
+ INFOPLIST_KEY_CFBundleDisplayName = RealChar;
497
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment";
498
+ INFOPLIST_KEY_NSMicrophoneUsageDescription = "You can send voice message to your favorite realtime AI chacater.";
499
+ INFOPLIST_KEY_NSSpeechRecognitionUsageDescription = "You can send voice message to your favorite realtime AI chacater.";
500
+ INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
501
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
502
+ INFOPLIST_KEY_UILaunchScreen_Generation = YES;
503
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
504
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
505
+ LD_RUNPATH_SEARCH_PATHS = (
506
+ "$(inherited)",
507
+ "@executable_path/Frameworks",
508
+ );
509
+ MARKETING_VERSION = 0.1;
510
+ PRODUCT_BUNDLE_IDENTIFIER = ai.realchar.app;
511
+ PRODUCT_NAME = "$(TARGET_NAME)";
512
+ SWIFT_EMIT_LOC_STRINGS = YES;
513
+ SWIFT_VERSION = 5.0;
514
+ TARGETED_DEVICE_FAMILY = "1,2";
515
+ };
516
+ name = Release;
517
+ };
518
+ /* End XCBuildConfiguration section */
519
+
520
+ /* Begin XCConfigurationList section */
521
+ 26FE4D002A5B6F0D006A1882 /* Build configuration list for PBXProject "rac" */ = {
522
+ isa = XCConfigurationList;
523
+ buildConfigurations = (
524
+ 26FE4D112A5B6F0E006A1882 /* Debug */,
525
+ 26FE4D122A5B6F0E006A1882 /* Release */,
526
+ );
527
+ defaultConfigurationIsVisible = 0;
528
+ defaultConfigurationName = Release;
529
+ };
530
+ 26FE4D132A5B6F0E006A1882 /* Build configuration list for PBXNativeTarget "rac" */ = {
531
+ isa = XCConfigurationList;
532
+ buildConfigurations = (
533
+ 26FE4D142A5B6F0E006A1882 /* Debug */,
534
+ 26FE4D152A5B6F0E006A1882 /* Release */,
535
+ );
536
+ defaultConfigurationIsVisible = 0;
537
+ defaultConfigurationName = Release;
538
+ };
539
+ /* End XCConfigurationList section */
540
+
541
+ /* Begin XCRemoteSwiftPackageReference section */
542
+ 2600B0792A61EA86003E8388 /* XCRemoteSwiftPackageReference "swiftui-cached-async-image" */ = {
543
+ isa = XCRemoteSwiftPackageReference;
544
+ repositoryURL = "https://github.com/lorenzofiamingo/swiftui-cached-async-image";
545
+ requirement = {
546
+ kind = upToNextMajorVersion;
547
+ minimumVersion = 2.0.0;
548
+ };
549
+ };
550
+ 2600B0812A68F585003E8388 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = {
551
+ isa = XCRemoteSwiftPackageReference;
552
+ repositoryURL = "https://github.com/firebase/firebase-ios-sdk";
553
+ requirement = {
554
+ kind = upToNextMajorVersion;
555
+ minimumVersion = 10.0.0;
556
+ };
557
+ };
558
+ 2600B08A2A68FC8C003E8388 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */ = {
559
+ isa = XCRemoteSwiftPackageReference;
560
+ repositoryURL = "https://github.com/google/GoogleSignIn-iOS";
561
+ requirement = {
562
+ kind = upToNextMajorVersion;
563
+ minimumVersion = 7.0.0;
564
+ };
565
+ };
566
+ /* End XCRemoteSwiftPackageReference section */
567
+
568
+ /* Begin XCSwiftPackageProductDependency section */
569
+ 2600B07A2A61EA86003E8388 /* CachedAsyncImage */ = {
570
+ isa = XCSwiftPackageProductDependency;
571
+ package = 2600B0792A61EA86003E8388 /* XCRemoteSwiftPackageReference "swiftui-cached-async-image" */;
572
+ productName = CachedAsyncImage;
573
+ };
574
+ 2600B0822A68F585003E8388 /* FirebaseAnalytics */ = {
575
+ isa = XCSwiftPackageProductDependency;
576
+ package = 2600B0812A68F585003E8388 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
577
+ productName = FirebaseAnalytics;
578
+ };
579
+ 2600B0842A68F585003E8388 /* FirebaseAuth */ = {
580
+ isa = XCSwiftPackageProductDependency;
581
+ package = 2600B0812A68F585003E8388 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
582
+ productName = FirebaseAuth;
583
+ };
584
+ 2600B0862A68F585003E8388 /* FirebaseAuthCombine-Community */ = {
585
+ isa = XCSwiftPackageProductDependency;
586
+ package = 2600B0812A68F585003E8388 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
587
+ productName = "FirebaseAuthCombine-Community";
588
+ };
589
+ 2600B08B2A68FC8C003E8388 /* GoogleSignInSwift */ = {
590
+ isa = XCSwiftPackageProductDependency;
591
+ package = 2600B08A2A68FC8C003E8388 /* XCRemoteSwiftPackageReference "GoogleSignIn-iOS" */;
592
+ productName = GoogleSignInSwift;
593
+ };
594
+ /* End XCSwiftPackageProductDependency section */
595
+ };
596
+ rootObject = 26FE4CFD2A5B6F0D006A1882 /* Project object */;
597
+ }
client/mobile/ios/rac/rac.xcodeproj/project.xcworkspace/contents.xcworkspacedata ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Workspace
3
+ version = "1.0">
4
+ <FileRef
5
+ location = "self:">
6
+ </FileRef>
7
+ </Workspace>
client/mobile/ios/rac/rac.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>IDEDidComputeMac32BitWarning</key>
6
+ <true/>
7
+ </dict>
8
+ </plist>
client/mobile/ios/rac/rac.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "pins" : [
3
+ {
4
+ "identity" : "abseil-cpp-binary",
5
+ "kind" : "remoteSourceControl",
6
+ "location" : "https://github.com/google/abseil-cpp-binary.git",
7
+ "state" : {
8
+ "revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c",
9
+ "version" : "1.2022062300.0"
10
+ }
11
+ },
12
+ {
13
+ "identity" : "appauth-ios",
14
+ "kind" : "remoteSourceControl",
15
+ "location" : "https://github.com/openid/AppAuth-iOS.git",
16
+ "state" : {
17
+ "revision" : "71cde449f13d453227e687458144bde372d30fc7",
18
+ "version" : "1.6.2"
19
+ }
20
+ },
21
+ {
22
+ "identity" : "firebase-ios-sdk",
23
+ "kind" : "remoteSourceControl",
24
+ "location" : "https://github.com/firebase/firebase-ios-sdk",
25
+ "state" : {
26
+ "revision" : "a580250a9ff49ec38da5430cef20f88ddc831db2",
27
+ "version" : "10.12.0"
28
+ }
29
+ },
30
+ {
31
+ "identity" : "googleappmeasurement",
32
+ "kind" : "remoteSourceControl",
33
+ "location" : "https://github.com/google/GoogleAppMeasurement.git",
34
+ "state" : {
35
+ "revision" : "0a226a8c50494c4cb877fbde27ab6374520a3354",
36
+ "version" : "10.12.0"
37
+ }
38
+ },
39
+ {
40
+ "identity" : "googledatatransport",
41
+ "kind" : "remoteSourceControl",
42
+ "location" : "https://github.com/google/GoogleDataTransport.git",
43
+ "state" : {
44
+ "revision" : "98a00258d4518b7521253a70b7f70bb76d2120fe",
45
+ "version" : "9.2.4"
46
+ }
47
+ },
48
+ {
49
+ "identity" : "googlesignin-ios",
50
+ "kind" : "remoteSourceControl",
51
+ "location" : "https://github.com/google/GoogleSignIn-iOS",
52
+ "state" : {
53
+ "revision" : "7932d33686c1dc4d7df7a919aae47361d1cdfda4",
54
+ "version" : "7.0.0"
55
+ }
56
+ },
57
+ {
58
+ "identity" : "googleutilities",
59
+ "kind" : "remoteSourceControl",
60
+ "location" : "https://github.com/google/GoogleUtilities.git",
61
+ "state" : {
62
+ "revision" : "4446686bc3714d49ce043d0f68318f42ed718cb6",
63
+ "version" : "7.11.4"
64
+ }
65
+ },
66
+ {
67
+ "identity" : "grpc-binary",
68
+ "kind" : "remoteSourceControl",
69
+ "location" : "https://github.com/google/grpc-binary.git",
70
+ "state" : {
71
+ "revision" : "f1b366129d1125be7db83247e003fc333104b569",
72
+ "version" : "1.50.2"
73
+ }
74
+ },
75
+ {
76
+ "identity" : "gtm-session-fetcher",
77
+ "kind" : "remoteSourceControl",
78
+ "location" : "https://github.com/google/gtm-session-fetcher.git",
79
+ "state" : {
80
+ "revision" : "d415594121c9e8a4f9d79cecee0965cf35e74dbd",
81
+ "version" : "3.1.1"
82
+ }
83
+ },
84
+ {
85
+ "identity" : "gtmappauth",
86
+ "kind" : "remoteSourceControl",
87
+ "location" : "https://github.com/google/GTMAppAuth.git",
88
+ "state" : {
89
+ "revision" : "cee3c709307912d040bd1e06ca919875a92339c6",
90
+ "version" : "2.0.0"
91
+ }
92
+ },
93
+ {
94
+ "identity" : "leveldb",
95
+ "kind" : "remoteSourceControl",
96
+ "location" : "https://github.com/firebase/leveldb.git",
97
+ "state" : {
98
+ "revision" : "0706abcc6b0bd9cedfbb015ba840e4a780b5159b",
99
+ "version" : "1.22.2"
100
+ }
101
+ },
102
+ {
103
+ "identity" : "nanopb",
104
+ "kind" : "remoteSourceControl",
105
+ "location" : "https://github.com/firebase/nanopb.git",
106
+ "state" : {
107
+ "revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692",
108
+ "version" : "2.30909.0"
109
+ }
110
+ },
111
+ {
112
+ "identity" : "promises",
113
+ "kind" : "remoteSourceControl",
114
+ "location" : "https://github.com/google/promises.git",
115
+ "state" : {
116
+ "revision" : "ec957ccddbcc710ccc64c9dcbd4c7006fcf8b73a",
117
+ "version" : "2.2.0"
118
+ }
119
+ },
120
+ {
121
+ "identity" : "swift-protobuf",
122
+ "kind" : "remoteSourceControl",
123
+ "location" : "https://github.com/apple/swift-protobuf.git",
124
+ "state" : {
125
+ "revision" : "f25867a208f459d3c5a06935dceb9083b11cd539",
126
+ "version" : "1.22.0"
127
+ }
128
+ },
129
+ {
130
+ "identity" : "swiftui-cached-async-image",
131
+ "kind" : "remoteSourceControl",
132
+ "location" : "https://github.com/lorenzofiamingo/swiftui-cached-async-image",
133
+ "state" : {
134
+ "revision" : "467a3d17479887943ab917a379e62bbaff60ac8a",
135
+ "version" : "2.1.1"
136
+ }
137
+ }
138
+ ],
139
+ "version" : 2
140
+ }
client/mobile/ios/rac/rac/Assets/Assets.xcassets/AccentColor.colorset/Contents.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "colors" : [
3
+ {
4
+ "color" : {
5
+ "color-space" : "display-p3",
6
+ "components" : {
7
+ "alpha" : "1.000",
8
+ "blue" : "255",
9
+ "green" : "177",
10
+ "red" : "148"
11
+ }
12
+ },
13
+ "idiom" : "universal"
14
+ }
15
+ ],
16
+ "info" : {
17
+ "author" : "xcode",
18
+ "version" : 1
19
+ }
20
+ }
client/mobile/ios/rac/rac/Assets/Assets.xcassets/AppIcon.appiconset/AppIcon.png ADDED
client/mobile/ios/rac/rac/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "images" : [
3
+ {
4
+ "filename" : "AppIcon.png",
5
+ "idiom" : "universal",
6
+ "platform" : "ios",
7
+ "size" : "1024x1024"
8
+ }
9
+ ],
10
+ "info" : {
11
+ "author" : "xcode",
12
+ "version" : 1
13
+ }
14
+ }
client/mobile/ios/rac/rac/Assets/Assets.xcassets/Contents.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "info" : {
3
+ "author" : "xcode",
4
+ "version" : 1
5
+ }
6
+ }
client/mobile/ios/rac/rac/Assets/Assets.xcassets/logo.imageset/Contents.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "images" : [
3
+ {
4
+ "filename" : "logo.svg",
5
+ "idiom" : "universal"
6
+ },
7
+ {
8
+ "appearances" : [
9
+ {
10
+ "appearance" : "luminosity",
11
+ "value" : "dark"
12
+ }
13
+ ],
14
+ "filename" : "logo_dark.svg",
15
+ "idiom" : "universal"
16
+ }
17
+ ],
18
+ "info" : {
19
+ "author" : "xcode",
20
+ "version" : 1
21
+ },
22
+ "properties" : {
23
+ "preserves-vector-representation" : true
24
+ }
25
+ }
client/mobile/ios/rac/rac/Assets/Assets.xcassets/logo.imageset/logo.svg ADDED
client/mobile/ios/rac/rac/Assets/Assets.xcassets/logo.imageset/logo_dark.svg ADDED
client/mobile/ios/rac/rac/Assets/Assets.xcassets/menu.imageset/Contents.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "images" : [
3
+ {
4
+ "filename" : "menu.svg",
5
+ "idiom" : "universal"
6
+ }
7
+ ],
8
+ "info" : {
9
+ "author" : "xcode",
10
+ "version" : 1
11
+ },
12
+ "properties" : {
13
+ "preserves-vector-representation" : true,
14
+ "template-rendering-intent" : "template"
15
+ }
16
+ }
client/mobile/ios/rac/rac/Assets/Assets.xcassets/menu.imageset/menu.svg ADDED
client/mobile/ios/rac/rac/Assets/Assets.xcassets/message.imageset/Contents.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "images" : [
3
+ {
4
+ "filename" : "message.svg",
5
+ "idiom" : "universal"
6
+ }
7
+ ],
8
+ "info" : {
9
+ "author" : "xcode",
10
+ "version" : 1
11
+ },
12
+ "properties" : {
13
+ "preserves-vector-representation" : true,
14
+ "template-rendering-intent" : "template"
15
+ }
16
+ }
client/mobile/ios/rac/rac/Assets/Assets.xcassets/message.imageset/message.svg ADDED
client/mobile/ios/rac/rac/Assets/Assets.xcassets/power.imageset/Contents.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "images" : [
3
+ {
4
+ "filename" : "power.svg",
5
+ "idiom" : "universal"
6
+ }
7
+ ],
8
+ "info" : {
9
+ "author" : "xcode",
10
+ "version" : 1
11
+ },
12
+ "properties" : {
13
+ "preserves-vector-representation" : true,
14
+ "template-rendering-intent" : "template"
15
+ }
16
+ }
client/mobile/ios/rac/rac/Assets/Assets.xcassets/power.imageset/power.svg ADDED
client/mobile/ios/rac/rac/Assets/Assets.xcassets/stop.imageset/Contents.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "images" : [
3
+ {
4
+ "filename" : "stop.svg",
5
+ "idiom" : "universal"
6
+ }
7
+ ],
8
+ "info" : {
9
+ "author" : "xcode",
10
+ "version" : 1
11
+ },
12
+ "properties" : {
13
+ "preserves-vector-representation" : true,
14
+ "template-rendering-intent" : "template"
15
+ }
16
+ }
client/mobile/ios/rac/rac/Assets/Assets.xcassets/stop.imageset/stop.svg ADDED
client/mobile/ios/rac/rac/Assets/Assets.xcassets/voice.imageset/Contents.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "images" : [
3
+ {
4
+ "filename" : "voice.svg",
5
+ "idiom" : "universal"
6
+ }
7
+ ],
8
+ "info" : {
9
+ "author" : "xcode",
10
+ "version" : 1
11
+ },
12
+ "properties" : {
13
+ "preserves-vector-representation" : true,
14
+ "template-rendering-intent" : "template"
15
+ }
16
+ }
client/mobile/ios/rac/rac/Assets/Assets.xcassets/voice.imageset/voice.svg ADDED
client/mobile/ios/rac/rac/Assets/Prompt-Medium.ttf ADDED
Binary file (170 kB). View file
 
client/mobile/ios/rac/rac/Assets/Prompt-Regular.ttf ADDED
Binary file (163 kB). View file
 
client/mobile/ios/rac/rac/Assets/Prompt-SemiBold.ttf ADDED
Binary file (169 kB). View file