Skip to content

Commit

Permalink
Merge pull request #88 from Aryamirsepasi/main
Browse files Browse the repository at this point in the history
Beta 5 of macOS Port
  • Loading branch information
theJayTea authored Dec 30, 2024
2 parents 9db0655 + 9b77a54 commit 0b0d150
Show file tree
Hide file tree
Showing 22 changed files with 1,736 additions and 481 deletions.
77 changes: 52 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ The macOS version is a **native Swift port**, developed by [Aryamirsepasi](https

To install it:
1. Go to the [Releases](https://github.com/theJayTea/WritingTools/releases) page and download the latest `.dmg` file.
2. Open the `.dmg` file and drag the `writing-tools.app` into the Applications folder. That's it!
2. Open the `.dmg` file, also open a Finder Window, and drag the `writing-tools.app` into the Applications folder. That's it!

## 👀 Tips

Expand Down Expand Up @@ -196,32 +196,59 @@ python pyinstaller-build-script.py
### macOS Version (by [Aryamirsepasi](https://github.com/Aryamirsepasi)) build instructions:

1. **Install Xcode**
- Ensure you have Xcode installed on your macOS system.
- Download it from the [Mac App Store](https://apps.apple.com/us/app/xcode/id497799835).
- Download and install Xcode from the App Store
- Launch Xcode once installed and complete any additional component installations

2. **Clone the Repository to your local machine**
```bash
git clone https://github.com/theJayTea/WritingTools.git
cd WritingTools
```

3. **Open the Project in Xcode**
- Open Xcode.
- Select **File > Open** from the menu bar.
- Navigate to the `macOS` folder and select it.

4. **Generate the Project File**
Run the following command to generate the `.xcodeproj` file:
```bash
swift package generate-xcodeproj
```

5. **Build the Project**
- Select your target device as **My Mac** in Xcode.
- Build the project by clicking the **Play** button (or pressing `Command + R`).
2. **Clone the Repository**
- Open Terminal and navigate to a directory you want the project to be in:
```bash
git clone https://github.com/theJayTea/WritingTools.git
cd WritingTools
```

6. **Run the App**
- After the build is successful, the app will launch automatically.
3. **Create Xcode Project**
- Navigate to the project's macOS directory:
```bash
cd macOS
```
- Create a new Xcode project:
```bash
xcodebuild -project writing-tools.xcodeproj
```

4. **Open in Xcode**
- Double-click the generated `writing-tools.xcodeproj` file
- Or open Xcode and select "Open a Project or File"
- Navigate to the `WritingTools/macOS/writing-tools.xcodeproj` file
5. **Configure Project Settings**
- In Xcode, select the project in the navigator
- Under "Targets", select "writing-tools"
- Set the following:
- Deployment Target: macOS 14.0
- Signing & Capabilities: Add your development team
6. **Install Dependencies**
- In Terminal, run:
```bash
cd macOS
swift package resolve
```
7. **Build and Run**
- In Xcode, select "My Mac" as the run destination
- Click the Play button or press ⌘R to build and run
## Troubleshooting
If you encounter the "Could not open file" error:
1. Ensure you're opening the `.xcodeproj` file, not the folder
2. If the error persists, try:
```bash
cd WritingTools/macOS
rm -rf writing-tools.xcodeproj
xcodebuild -project writing-tools.xcodeproj
```
## 🌟 Contributors
Expand Down
173 changes: 106 additions & 67 deletions macOS/README.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,106 @@
# Writing Tools for macOS

This is a new, **native macOS port of Writing Tools**, created entirely by @Aryamirsepasi 🎉

Core functionality works well, and it is still an ongoing work in progress.

---

## Working Features
- All of the tools, including the new response windows and the manual chat option.
- Input Window even when no text is selected
- Gemini, OpenAI and Local LLM Support.
- The Gradient Theme (Dark Mode and Light Mode are supported).
- Initial Setup, Settings, and About pages.

---

## Not Yet Available
- All of the original port's features are now available; however, more optimizations and improvements are coming soon.

---

## System Requirements
Due to the accessibility features the app uses (e.g., automatically selecting the window containing the text and pasting the updated version), **the minimum macOS version required is 14.0**.

---

## How to Build This Project

Since the `.xcodeproj` file is excluded, you can still build the project manually by following these steps:

1. **Install Xcode**
- Ensure you have Xcode installed on your macOS system.
- Download it from the [Mac App Store](https://apps.apple.com/us/app/xcode/id497799835).

2. **Clone the Repository**
- Clone this repository to your local machine:
```bash
git clone https://github.com/theJayTea/WritingTools.git
cd WritingTools
```

3. **Open the Project in Xcode**
- Open Xcode.
- Select **File > Open** from the menu bar.
- Navigate to the `macOS` folder and select it.

4. **Generate the Project File**
- Run the following command to generate the `.xcodeproj` file:
```bash
swift package generate-xcodeproj
```

5. **Build the Project**
- Select your target device as **My Mac** in Xcode.
- Build the project by clicking the **Play** button (or pressing `Command + R`).

6. **Run the App**
- After the build is successful, the app will launch automatically.

---

## Credits

The macOS port is being developed by **Aryamirsepasi**.

GitHub: [https://github.com/Aryamirsepasi](https://github.com/Aryamirsepasi)
# Writing Tools for macOS

This is a new, **native macOS port of Writing Tools**, created entirely by @Aryamirsepasi 🎉

Core functionality works well, and it is still an ongoing work in progress.

---

## Working Features
- All of the tools, including the new response windows and the manual chat option.
- Input Window even when no text is selected
- Gemini, OpenAI and Local LLM Support.
- The Gradient Theme (Dark Mode and Light Mode are supported).
- Initial Setup, Settings, and About pages.

---

## Not Yet Available
- All of the original port's features are now available; however, more optimizations and improvements are coming soon.

---

## System Requirements
Due to the accessibility features the app uses (e.g., automatically selecting the window containing the text and pasting the updated version), **the minimum macOS version required is 14.0**.

---

## How to Build This Project

Since the `.xcodeproj` file is excluded, you can still build the project manually by following these steps:
This guide will help you properly set up the Writing Tools macOS project in Xcode.

## System Requirements
- macOS 14.0 or later
- Xcode 15.0 or later
- Git

## Installation Steps

1. **Install Xcode**
- Download and install Xcode from the App Store
- Launch Xcode once installed and complete any additional component installations

2. **Clone the Repository**
- Open Terminal and navigate to a directory you want the project to be in:
```bash
git clone https://github.com/theJayTea/WritingTools.git
cd WritingTools
```

3. **Create Xcode Project**
- Navigate to the project's macOS directory:
```bash
cd macOS
```
- Create a new Xcode project:
```bash
xcodebuild -project writing-tools.xcodeproj
```

4. **Open in Xcode**
- Double-click the generated `writing-tools.xcodeproj` file
- Or open Xcode and select "Open a Project or File"
- Navigate to the `WritingTools/macOS/writing-tools.xcodeproj` file
5. **Configure Project Settings**
- In Xcode, select the project in the navigator
- Under "Targets", select "writing-tools"
- Set the following:
- Deployment Target: macOS 14.0
- Signing & Capabilities: Add your development team
6. **Install Dependencies**
- In Terminal, run:
```bash
cd macOS
swift package resolve
```
7. **Build and Run**
- In Xcode, select "My Mac" as the run destination
- Click the Play button or press ⌘R to build and run
## Troubleshooting
If you encounter the "Could not open file" error:
1. Ensure you're opening the `.xcodeproj` file, not the folder
2. If the error persists, try:
```bash
cd WritingTools/macOS
rm -rf writing-tools.xcodeproj
xcodebuild -project writing-tools.xcodeproj
```
## Additional Notes
- The project requires macOS 14.0+ due to accessibility features
- Make sure all required permissions are granted when first launching the app
- For development, ensure you have the latest Xcode Command Line Tools installed
---
## Credits
The macOS port is being developed by **Aryamirsepasi**.
GitHub: [https://github.com/Aryamirsepasi](https://github.com/Aryamirsepasi)
6 changes: 6 additions & 0 deletions macOS/writing-tools/AI Providers/AIProvider.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import Foundation

protocol AIProvider: ObservableObject {

// Indicates if provider is processing a request
var isProcessing: Bool { get set }

// Process text with optional system prompt
func processText(systemPrompt: String?, userPrompt: String) async throws -> String

// Cancel ongoing requests
func cancel()
}
65 changes: 30 additions & 35 deletions macOS/writing-tools/AI Providers/GeminiProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,32 @@ struct GeminiConfig: Codable {
}

enum GeminiModel: String, CaseIterable {
case flash8b = "gemini-1.5-flash-8b-latest"
case flash = "gemini-1.5-flash-latest"
case pro = "gemini-1.5-pro-latest"
case oneflash8b = "gemini-1.5-flash-8b-latest"
case oneflash = "gemini-1.5-flash-latest"
case onepro = "gemini-1.5-pro-latest"
case twoflash = "gemini-2.0-flash-exp"

var displayName: String {
switch self {
case .flash8b: return "Gemini 1.5 Flash 8B (fast)"
case .flash: return "Gemini 1.5 Flash (fast & more intelligent, recommended)"
case .pro: return "Gemini 1.5 Pro (very intelligent, but slower & lower rate limit)"
case .oneflash8b: return "Gemini 1.5 Flash 8B (fast)"
case .oneflash: return "Gemini 1.5 Flash (fast & more intelligent)"
case .onepro: return "Gemini 1.5 Pro (very intelligent, but slower & lower rate limit)"
case .twoflash: return "Gemini 2.0 Flash (extremely intelligent & fast, recommended)"
}
}
}

class GeminiProvider: ObservableObject, AIProvider {
@Published var isProcessing = false
private var config: GeminiConfig
private var currentTask: URLSessionDataTask?

init(config: GeminiConfig) {
self.config = config
}

func processText(systemPrompt: String? = "You are a helpful writing assistant.", userPrompt: String) async throws -> String {
isProcessing = true
defer { isProcessing = false }

let finalPrompt = systemPrompt.map { "\($0)\n\n\(userPrompt)" } ?? userPrompt

Expand All @@ -55,38 +58,30 @@ class GeminiProvider: ObservableObject, AIProvider {
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONSerialization.data(withJSONObject: requestBody, options: .fragmentsAllowed)

do {
isProcessing = true
let (data, response) = try await URLSession.shared.data(for: request)

guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw NSError(domain: "GeminiAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "Server returned an error."])
}

guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
throw NSError(domain: "GeminiAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to parse JSON response."])
}

guard let candidates = json["candidates"] as? [[String: Any]], !candidates.isEmpty else {
throw NSError(domain: "GeminiAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "No candidates found in the response."])
}

if let content = candidates.first?["content"] as? [String: Any],
let parts = content["parts"] as? [[String: Any]],
let text = parts.first?["text"] as? String {
return text
}

throw NSError(domain: "GeminiAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "No valid content in response."])
} catch {
isProcessing = false
print("Error processing JSON: \(error.localizedDescription)")
throw NSError(domain: "GeminiAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "Error processing text: \(error.localizedDescription)"])
let (data, response) = try await URLSession.shared.data(for: request)

guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw NSError(domain: "GeminiAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "Server returned an error."])
}

guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
throw NSError(domain: "GeminiAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to parse JSON response."])
}

guard let candidates = json["candidates"] as? [[String: Any]], !candidates.isEmpty else {
throw NSError(domain: "GeminiAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "No candidates found in the response."])
}

if let content = candidates.first?["content"] as? [String: Any],
let parts = content["parts"] as? [[String: Any]],
let text = parts.first?["text"] as? String {
return text
}

throw NSError(domain: "GeminiAPI", code: -1, userInfo: [NSLocalizedDescriptionKey: "No valid content in response."])
}

func cancel() {
currentTask?.cancel()
isProcessing = false
}
}
Loading

0 comments on commit 0b0d150

Please sign in to comment.