Add RealChar deployment for HuggingFace (V0)
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- CHANGELOG.md +22 -0
- Dockerfile +22 -0
- LICENSE +21 -0
- README.md +276 -11
- alembic.ini +110 -0
- alembic/README +1 -0
- alembic/__pycache__/env.cpython-311.pyc +0 -0
- alembic/env.py +92 -0
- alembic/script.py.mako +24 -0
- alembic/versions/0f355a71adbb_added_interaction_table.py +32 -0
- alembic/versions/27fe156a6d72_change_schema_to_unicode.py +28 -0
- alembic/versions/3821f7adaca9_add_session_id.py +25 -0
- alembic/versions/9ed6d1431c1d_add_platform_and_action_types.py +28 -0
- alembic/versions/__pycache__/0f355a71adbb_added_interaction_table.cpython-311.pyc +0 -0
- alembic/versions/__pycache__/27fe156a6d72_change_schema_to_unicode.cpython-311.pyc +0 -0
- alembic/versions/__pycache__/3821f7adaca9_add_session_id.cpython-311.pyc +0 -0
- alembic/versions/__pycache__/9ed6d1431c1d_add_platform_and_action_types.cpython-311.pyc +0 -0
- alembic/versions/__pycache__/c3a93ef3de5d_drop_client_id_column.cpython-311.pyc +0 -0
- alembic/versions/__pycache__/ead242c61258_added_user_table.cpython-311.pyc +0 -0
- alembic/versions/__pycache__/eced1ae3918a_add_string_user_id.cpython-311.pyc +0 -0
- alembic/versions/ead242c61258_added_user_table.py +32 -0
- alembic/versions/eced1ae3918a_add_string_user_id.py +35 -0
- cli.py +77 -0
- client/README.md +11 -0
- client/cli.py +278 -0
- client/mobile/ios/.gitignore +175 -0
- client/mobile/ios/rac/rac.xcodeproj/project.pbxproj +597 -0
- client/mobile/ios/rac/rac.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- client/mobile/ios/rac/rac.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- client/mobile/ios/rac/rac.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +140 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/AccentColor.colorset/Contents.json +20 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/AppIcon.appiconset/AppIcon.png +0 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/Contents.json +6 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/logo.imageset/Contents.json +25 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/logo.imageset/logo.svg +11 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/logo.imageset/logo_dark.svg +11 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/menu.imageset/Contents.json +16 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/menu.imageset/menu.svg +9 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/message.imageset/Contents.json +16 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/message.imageset/message.svg +5 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/power.imageset/Contents.json +16 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/power.imageset/power.svg +5 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/stop.imageset/Contents.json +16 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/stop.imageset/stop.svg +5 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/voice.imageset/Contents.json +16 -0
- client/mobile/ios/rac/rac/Assets/Assets.xcassets/voice.imageset/voice.svg +3 -0
- client/mobile/ios/rac/rac/Assets/Prompt-Medium.ttf +0 -0
- client/mobile/ios/rac/rac/Assets/Prompt-Regular.ttf +0 -0
- 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 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|