Last active
July 8, 2024 13:56
-
-
Save rcarmo/f96c659f149e357e1091cbfe352af6d4 to your computer and use it in GitHub Desktop.
macOS Services in the style of NotesOllama
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
# Drop this into Automator using Python 3 as the shell | |
from sys import stdin | |
from json import dumps, loads | |
from urllib.parse import urlencode | |
from urllib.request import Request, urlopen | |
AZURE_ENDPOINT="getyourowndeployment.openai.azure.com" | |
OPENAI_API_KEY="getyourownkey" | |
OPENAI_API_VERSION="2023-05-15" | |
DEPLOYMENT_NAME="default" # I've deployed chatgpt35-turbo under this label | |
url = f"https://{AZURE_ENDPOINT}/openai/deployments/{DEPLOYMENT_NAME}/chat/completions?api-version={OPENAI_API_VERSION}" | |
headers = {"api-key": OPENAI_API_KEY, "content-type": "application/json; charset=UTF-8"} | |
prompts = [ # shamelessly stolen from https://github.com/andersrex/notesollama/blob/main/NotesOllama/Menu/commands.swift (MIT licensed) | |
{ | |
"name": "Summarize selection", | |
"prompt": "Act as a writer. Summarize the text in a view sentences highlighting the key takeaways. Output only the text and nothing else, do not chat, no preamble, get to the point." | |
}, | |
{ | |
"name": "Explain selection", | |
"prompt": "Act as a writer. Explain the text in simple and concise terms keeping the same meaning. Output only the text and nothing else, do not chat, no preamble, get to the point." | |
}, | |
{ | |
"name": "Expand selection", | |
"prompt": "Act as a writer. Expand the text by adding more details while keeping the same meaning. Output only the text and nothing else, do not chat, no preamble, get to the point." | |
}, | |
{ | |
"name": "Answer selection", | |
"prompt": "Act as a writer. Answer the question in the text in simple and concise terms. Output only the text and nothing else, do not chat, no preamble, get to the point." | |
}, | |
{ | |
"name": "Rewrite selection (formal)", | |
"prompt": "Act as a writer. Rewrite the text in a more formal style while keeping the same meaning. Output only the text and nothing else, do not chat, no preamble, get to the point." | |
}, | |
{ | |
"name": "Rewrite selection (casual)", | |
"prompt": "Act as a writer. Rewrite the text in a more casual style while keeping the same meaning. Output only the text and nothing else, do not chat, no preamble, get to the point." | |
}, | |
{ | |
"name": "Rewrite selection (active voice)", | |
"prompt": "Act as a writer. Rewrite the text in with an active voice while keeping the same meaning. Output only the text and nothing else, do not chat, no preamble, get to the point." | |
}, | |
{ | |
"name": "Rewrite selection (bullet points)", | |
"prompt": "Act as a writer. Rewrite the text into bullet points while keeping the same meaning. Output only the text and nothing else, do not chat, no preamble, get to the point." | |
}, | |
{ | |
"name": "Caption selection", | |
"prompt": "Act as a writer. Create only one single heading for the whole text that is giving a good understanding of what the reader can expect. Output only the caption and nothing else, do not chat, no preamble, get to the point. Your format should be ## Caption." | |
} | |
] | |
prompt = prompts[0]["prompt"] # adjust the index to select a different prompt | |
data = { | |
"temperature": 0.4, | |
"messages": [{ | |
"role": "system", | |
"content": prompt | |
},{ | |
"role": "user", | |
"content": stdin.read() | |
}]#,{ | |
# role: "assistant", | |
# Use this to guide the LLM if you need JSON formatting | |
# content: "" | |
#} | |
} | |
req = Request(url, data=dumps(data).encode(), method="POST", headers=headers) | |
with urlopen(req) as response: | |
print(loads(response.read().decode())["choices"][0]["message"]["content"]) |
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
function run(input, parameters) { | |
// This script is a simple example of how to use the Azure OpenAI API to generate text | |
// from a macOS system service written as a JavaScript for Automation (JXA) script | |
// You can drop this into a Shortcuts "Run JavaScript" action (which will only work on a Mac) | |
// or use it as a starting point for a more complex system service | |
ObjC.import('Foundation') | |
ObjC.import('Cocoa') | |
let app = Application.currentApplication(); | |
app.includeStandardAdditions = true | |
let AZURE_ENDPOINT = "my_endpoint.openai.azure.com", | |
DEPLOYMENT_NAME = "my_deployment", | |
// You should store your keys in the macOS Keychain and retrieve them from there: | |
OPENAI_API_KEY = app.doShellScript(`security find-generic-password -w -s ${AZURE_ENDPOINT} -a ${DEPLOYMENT_NAME}`) | |
OPENAI_API_VERSION = "2023-05-15", | |
url = `https://${AZURE_ENDPOINT}/openai/deployments/${DEPLOYMENT_NAME}/chat/completions?api-version=${OPENAI_API_VERSION}`, | |
postData = { | |
"temperature": 0.4, | |
"messages": [{ | |
"role": "system", | |
"content": "Act as a writer. Expand the text by adding more details while keeping the same meaning. Output only the text and nothing else, do not chat, no preamble, get to the point." | |
, | |
}, { | |
"role": "user", | |
"content": input.join("\n") | |
}]/*,{ | |
role: "assistant", | |
Use this if you need JSON formatting | |
content: "" | |
*/ | |
}, | |
request = $.NSMutableURLRequest.requestWithURL($.NSURL.URLWithString(url)); | |
request.setHTTPMethod("POST"); | |
request.setHTTPBody($.NSString.alloc.initWithUTF8String(JSON.stringify(postData)).dataUsingEncoding($.NSUTF8StringEncoding)); | |
request.setValueForHTTPHeaderField("application/json; charset=UTF-8", "Content-Type"); | |
request.setValueForHTTPHeaderField(OPENAI_API_KEY, "api-key"); | |
let error = $(), | |
response = $(), | |
data = $.NSURLConnection.sendSynchronousRequestReturningResponseError(request, response, error); | |
if (error[0]) { | |
return "Error: " + error[0].localizedDescription; | |
} else { | |
var json = JSON.parse($.NSString.alloc.initWithDataEncoding(data, $.NSUTF8StringEncoding).js); | |
if (json.error) { | |
return json.error.message; | |
} else { | |
return json.choices[0].message.content; | |
} | |
} | |
} |
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
import Cocoa | |
let url = URL(string:"https://endpoint_name.openai.azure.com/openai/deployments/deployment_name/chat/completions?api-version=2023-05-15")!, | |
prompt = "Do what you are told. No more, no less." | |
struct Role: Codable { | |
let role: String | |
let content: String | |
} | |
struct Completion: Codable { | |
let temperature: Float | |
let messages: [Role] | |
} | |
struct Response: Codable { | |
let id: String | |
let object: String | |
let created: Int | |
let model: String | |
let choices: [Choice] | |
let usage: Usage | |
} | |
struct Choice: Codable { | |
let finish_reason: String | |
let index: Int | |
let message: Message | |
} | |
struct Message: Codable { | |
let role: String | |
let content: String | |
} | |
struct Usage: Codable { | |
let prompt_tokens: Int | |
let completion_tokens: Int | |
let total_tokens: Int | |
} | |
let data = Completion( | |
temperature: 0.4, | |
messages: [ | |
Role(role:"system", content: prompt), | |
Role(role:"user", content: "Say Hello") | |
] | |
) | |
let encoder = JSONEncoder() | |
if let jsonData = try? encoder.encode(data), | |
let jsonString = String(data: jsonData, encoding: .utf8) { | |
print(jsonString) | |
var request = URLRequest(url: url); | |
request.httpMethod = "POST" | |
request.httpBody = jsonData | |
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type") | |
request.setValue("an_api_key", forHTTPHeaderField: "api-key") | |
let task = URLSession.shared.dataTask(with: request) { data, response, error in | |
guard let data = data, error == nil else { | |
print(error?.localizedDescription ?? "No data") | |
return | |
} | |
let decoder = JSONDecoder() | |
do { | |
let response = try decoder.decode(Response.self, from: data) | |
print(response.choices[0].message.content) | |
} catch { | |
print("Error decoding JSON: \(error)") | |
} | |
} | |
// note that this also makes it hard to handle control flow | |
task.resume() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment