-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #155 from dcSpark/feature/add-macos-say-text-to-au…
…dio-tool feat: add macos-say-text-to-audio tool
- Loading branch information
Showing
6 changed files
with
161 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { expect } from '@jest/globals'; | ||
import { getToolTestClient } from '../../src/test/utils'; | ||
import * as path from 'path'; | ||
|
||
describe('macOS Text-to-Speech', () => { | ||
const toolPath = path.join(__dirname, 'tool.py'); | ||
const client = getToolTestClient(); | ||
|
||
it('speaks text with default voice and rate', async () => { | ||
const response = await client.executeToolFromFile( | ||
toolPath, | ||
{ text: "Hello from text to speech test" }, | ||
{}, | ||
[] | ||
); | ||
|
||
expect(response).toHaveProperty('success', true); | ||
expect(response.message).toMatch(/Spoke text with voice=Alex/); | ||
}, 15000); | ||
|
||
it('handles empty text gracefully', async () => { | ||
await expect( | ||
client.executeToolFromFile(toolPath, { text: '' }, {}, []) | ||
).rejects.toThrow(/No text provided/); | ||
}); | ||
|
||
it('respects custom voice and rate', async () => { | ||
const response = await client.executeToolFromFile( | ||
toolPath, | ||
{ | ||
text: "Testing custom voice and rate", | ||
voice: "Daniel", | ||
rate: 200 | ||
}, | ||
{}, | ||
[] | ||
); | ||
expect(response.success).toBe(true); | ||
expect(response.message).toMatch(/voice=Daniel/); | ||
expect(response.message).toMatch(/rate=200/); | ||
}, 15000); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
{ | ||
"id": "macos-say-text-to-audio", | ||
"version": "1.0.0", | ||
"name": "macOS Text-to-Speech", | ||
"description": "Speaks text aloud using macOS 'say' command. Available voices can be found by running 'say -v ?' in terminal, common voices include: Alex (default), Daniel, Karen, Samantha, Victoria", | ||
"author": "Shinkai", | ||
"keywords": [ | ||
"macos", | ||
"say", | ||
"text-to-speech", | ||
"audio" | ||
], | ||
"configurations": { | ||
"type": "object", | ||
"properties": {}, | ||
"required": [] | ||
}, | ||
"parameters": { | ||
"type": "object", | ||
"properties": { | ||
"text": { | ||
"type": "string", | ||
"description": "The text to convert to speech" | ||
}, | ||
"voice": { | ||
"type": "string", | ||
"description": "The voice to use (e.g., Alex, Daniel, Karen)", | ||
"default": "Alex" | ||
} | ||
}, | ||
"required": ["text"] | ||
}, | ||
"result": { | ||
"type": "object", | ||
"properties": { | ||
"success": { | ||
"type": "boolean", | ||
"description": "Whether the text was successfully converted to speech" | ||
}, | ||
"message": { | ||
"type": "string", | ||
"description": "Success or error message" | ||
} | ||
}, | ||
"required": ["success", "message"] | ||
}, | ||
"sqlTables": [], | ||
"sqlQueries": [], | ||
"tools": [ | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"categoryId": "5f10d0b4-6acd-477a-96e1-be35634465b2" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# /// script | ||
# dependencies = [ | ||
# "requests" | ||
# ] | ||
# /// | ||
|
||
import subprocess | ||
import sys | ||
from typing import Dict, Any, Optional, List | ||
|
||
class CONFIG: | ||
""" | ||
No configurations needed for this tool by default. | ||
But you could expand if you need environment checks, etc. | ||
""" | ||
pass | ||
|
||
class INPUTS: | ||
text: str # The text to speak | ||
voice: str = "Alex" # A valid macOS voice, e.g. "Alex", "Daniel", "Victoria", etc. | ||
rate: int = 175 # Words per minute. Mac `say` defaults around 175 | ||
background: bool = False | ||
|
||
class OUTPUT: | ||
success: bool | ||
message: str | ||
|
||
async def run(c: CONFIG, p: INPUTS) -> OUTPUT: | ||
""" | ||
Speaks out the given text on macOS using the 'say' command. | ||
""" | ||
# Validate platform | ||
if sys.platform != 'darwin': | ||
raise RuntimeError("This tool only works on macOS systems") | ||
|
||
# Validate inputs | ||
text = p.text.strip() | ||
if not text: | ||
raise ValueError("No text provided to speak.") | ||
if p.rate < 1 or p.rate > 500: | ||
raise ValueError("Rate must be between 1 and 500 words per minute.") | ||
|
||
# Build shell command | ||
# Example: say -v "Alex" -r 175 "Hello world" | ||
# If background is True, add an ampersand at the end (shell background). | ||
voice_arg = f'-v "{p.voice}"' | ||
rate_arg = f'-r {p.rate}' | ||
quoted_text = text.replace('"', '\\"') # Escape double quotes | ||
cmd = f'say {voice_arg} {rate_arg} "{quoted_text}"' | ||
if p.background: | ||
cmd += " &" | ||
|
||
# Run the command | ||
try: | ||
subprocess.run(cmd, shell=True, check=True) | ||
success = True | ||
message = f"Spoke text with voice={p.voice}, rate={p.rate}, background={p.background}" | ||
except subprocess.CalledProcessError as e: | ||
success = False | ||
message = f"Failed to speak text: {str(e)}" | ||
|
||
output = OUTPUT() | ||
output.success = success | ||
output.message = message | ||
return output |