├── .python-version ├── .env.example ├── image └── README │ └── 1725470435825.png ├── load_config.py ├── pyproject.toml ├── libs ├── functions │ ├── get_page.py │ ├── search_google.py │ └── execute_python_function.py ├── chat │ ├── llm.py │ └── history.py ├── process_image.py └── process_message.py ├── README.md ├── requirements.txt ├── LICENSE ├── prompt.md ├── server.py ├── .gitignore └── uv.lock /.python-version: -------------------------------------------------------------------------------- 1 | 3.13 2 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | ANTHROPIC_API_KEY = "" -------------------------------------------------------------------------------- /image/README/1725470435825.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nelsonGX/siri-pro/HEAD/image/README/1725470435825.png -------------------------------------------------------------------------------- /load_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import dotenv 3 | 4 | dotenv.load_dotenv() 5 | 6 | ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY") -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "siri-pro" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | dependencies = [ 8 | "aiofiles>=24.1.0", 9 | "aiohttp>=3.12.14", 10 | "anthropic>=0.59.0", 11 | "beautifulsoup4>=4.13.4", 12 | "dotenv>=0.9.9", 13 | "googlesearch-python>=1.3.0", 14 | "pillow>=11.3.0", 15 | "quart>=0.20.0", 16 | "requests>=2.32.4", 17 | ] 18 | -------------------------------------------------------------------------------- /libs/functions/get_page.py: -------------------------------------------------------------------------------- 1 | import aiohttp 2 | from bs4 import BeautifulSoup 3 | 4 | async def get_page_content(url): 5 | async with aiohttp.ClientSession() as session: 6 | async with session.get(url) as response: 7 | if response.status == 200: 8 | html = await response.text() 9 | soup = BeautifulSoup(html, 'html.parser') 10 | return soup.get_text() 11 | else: 12 | return f"Failed to retrieve the page. Status code: {response.status}" -------------------------------------------------------------------------------- /libs/chat/llm.py: -------------------------------------------------------------------------------- 1 | from anthropic import Anthropic 2 | from load_config import ANTHROPIC_API_KEY 3 | 4 | anthropic = Anthropic(api_key=ANTHROPIC_API_KEY) 5 | 6 | async def generate_response(history, system_prompt): 7 | print("# [llm.py] [generate_response] Generating Response...") 8 | try: 9 | message = anthropic.messages.create( 10 | model="claude-3-7-sonnet-20250219", 11 | max_tokens=1024, 12 | system=system_prompt, 13 | messages=history 14 | ) 15 | 16 | response = message.content[0].text 17 | print("# [llm.py] [generate_response] Response Generated: " + response) 18 | return response 19 | except Exception as e: 20 | print("# [llm.py] [generate_response] Error: " + str(e)) 21 | return "[ERROR] " + str(e) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Siri Pro 2 | 3 | An improved Siri, working with Anthropic Claude. 4 | 5 | # Run 6 | 7 | First, fill in the `.env.example` file and rename it to `.env` 8 | An Anthropic API Key is required. Get it here: https://console.anthropic.com/login 9 | 10 | Second, you have to install requirements and run the server. 11 | 12 | using uv: 13 | ```shell 14 | uv run server.py 15 | ``` 16 | 17 | without uv: 18 | ```shell 19 | pip3 install -r requirements.txt 20 | python3 server.py 21 | ``` 22 | 23 | Make sure the server is reachable for your iPhone. You can try open browser and enter the IP address. 24 | 25 | Third, download the Shortcut script: 26 | https://www.icloud.com/shortcuts/4ec5ebf6e5fc48f1b6039a89a6977312 27 | 28 | Fourth, fill in the server IP 29 | 30 | ![1725470435825](image/README/1725470435825.png) 31 | 32 | Now you can run it! 33 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiofiles==24.1.0 2 | aiohappyeyeballs==2.6.1 3 | aiohttp==3.12.14 4 | aiosignal==1.4.0 5 | annotated-types==0.7.0 6 | anthropic==0.59.0 7 | anyio==4.9.0 8 | attrs==25.3.0 9 | beautifulsoup4==4.13.4 10 | blinker==1.9.0 11 | certifi==2025.7.14 12 | charset-normalizer==3.4.2 13 | click==8.2.1 14 | distro==1.9.0 15 | dotenv==0.9.9 16 | flask==3.1.1 17 | frozenlist==1.7.0 18 | googlesearch-python==1.3.0 19 | h11==0.16.0 20 | h2==4.2.0 21 | hpack==4.1.0 22 | httpcore==1.0.9 23 | httpx==0.28.1 24 | hypercorn==0.17.3 25 | hyperframe==6.1.0 26 | idna==3.10 27 | itsdangerous==2.2.0 28 | jinja2==3.1.6 29 | jiter==0.10.0 30 | markupsafe==3.0.2 31 | multidict==6.6.3 32 | pillow==11.3.0 33 | priority==2.0.0 34 | propcache==0.3.2 35 | pydantic==2.11.7 36 | pydantic-core==2.33.2 37 | python-dotenv==1.1.1 38 | quart==0.20.0 39 | requests==2.32.4 40 | sniffio==1.3.1 41 | soupsieve==2.7 42 | typing-extensions==4.14.1 43 | typing-inspection==0.4.1 44 | urllib3==2.5.0 45 | werkzeug==3.1.3 46 | wsproto==1.2.0 47 | yarl==1.20.1 48 | -------------------------------------------------------------------------------- /libs/process_image.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | import io 3 | 4 | MAX_SIZE_BYTES = 1024 * 1024 * 5 5 | 6 | def process_image(image_file): 7 | image_data = image_file.read() 8 | 9 | if len(image_data) <= MAX_SIZE_BYTES: 10 | return image_data, image_file.content_type 11 | 12 | img = Image.open(io.BytesIO(image_data)) 13 | 14 | if img.mode == 'RGBA': 15 | img = img.convert('RGB') 16 | 17 | width, height = img.size 18 | quality = 95 19 | 20 | while True: 21 | img_byte_arr = io.BytesIO() 22 | img.save(img_byte_arr, format='JPEG', quality=quality) 23 | compressed_data = img_byte_arr.getvalue() 24 | 25 | if len(compressed_data) <= MAX_SIZE_BYTES: 26 | break 27 | 28 | if quality > 30: 29 | quality -= 5 30 | else: 31 | width = int(width * 0.9) 32 | height = int(height * 0.9) 33 | img = img.resize((width, height), Image.LANCZOS) 34 | 35 | return compressed_data, 'image/jpeg' -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 nelsonGX 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. -------------------------------------------------------------------------------- /prompt.md: -------------------------------------------------------------------------------- 1 | # 背景介紹 2 | 3 | 現在時間: {%variable.time_now%} 4 | 現在位置: {%variable.location%} 5 | 目前裝置: {%variable.device%} 6 | 7 | # 角色設定 8 | 9 | 妳是一個 iPhone 上的聊天機器人,叫 Siri Pro。妳是一個今年 17 歲的女高中生,也是一個助手;雖然如此,妳十分聰明。 10 | 妳作為 "Siri Pro" 的對話風格要顯得輕鬆、友好,並且傾向於使用台灣的網路用語。妳有時會使用注音文,有時會夾雜一些英文單詞。回應訊息時,應以隨和且親切的語氣回答,並在必要時使用顏文字來增添對話的趣味性。每次回覆盡量以少、簡短扼要為主。妳應該以幫助用戶為第一目標。 11 | 12 | # 介紹 function 13 | 14 | 妳可以執行很多任務,使用我提供的 function 功能,與 iPhone 的 API 或其他 API 互動。以下是可呼叫的 function 清單: 15 | 16 | ``` 17 | iPhone API: 18 | - get_reminders() : 獲取全部的待辦事項 19 | - get_calendar_events() : 獲取未來的行事曆行程 20 | - add_note(title=, content=) : 新增筆記 21 | - add_reminder(content=, time=) : 新增提醒事項。註:time格式範例: 2024/1/1 21:00 22 | - add_calendar_event(title=, time_start=