Browse Source

Merge branch 'development'

pull/201/head
Meir Michanie 1 year ago
parent
commit
368916b0ab
  1. 17
      installer/client/cli/fabric.py
  2. 55
      installer/client/cli/utils.py
  3. 6
      installer/client/gui/chatgpt.js
  4. 10
      installer/client/gui/index.html
  5. 52
      installer/client/gui/main.js
  6. 19
      installer/client/gui/static/js/index.js
  7. 1
      testmessage.txt

17
installer/client/cli/fabric.py

@ -58,6 +58,7 @@ def main():
help='The URL of the remote ollamaserver to use. ONLY USE THIS if you are using a local ollama server in an non-deault location or port')
parser.add_argument('--context', '-c',
help="Use Context file (context.md) to add context to your pattern", action="store_true")
parser.add_argument('files', nargs='*', help='Files to read from (reads from stdin if not provided)')
args = parser.parse_args()
home_holder = os.path.expanduser("~")
@ -130,7 +131,21 @@ def main():
if args.text is not None:
text = args.text
else:
text = standalone.get_cli_input()
if args.files:
text = ""
for file in args.files:
try:
with open(file, "r") as f:
text += f.read()
except FileNotFoundError:
print(f"File {file} not found")
sys.exit()
except Exception as e:
print(f"An error occurred: {e}")
sys.exit()
else:
text = standalone.get_cli_input()
if args.stream and not args.context:
if args.remoteOllamaServer:
standalone.streamMessage(text, host=args.remoteOllamaServer)

55
installer/client/cli/utils.py

@ -36,12 +36,17 @@ class Standalone:
# Expand the tilde to the full path
env_file = os.path.expanduser(env_file)
load_dotenv(env_file)
try:
apikey = os.environ["OPENAI_API_KEY"]
if "OPENAI_API_KEY" not in os.environ:
print("Error: OPENAI_API_KEY not found in environment variables.")
self.client = OpenAI()
self.client.api_key = apikey
except:
print("No API key found. Use the --apikey option to set the key")
else:
api_key = os.environ['OPENAI_API_KEY']
base_url = os.environ.get('OPENAI_BASE_URL')
if base_url:
self.client = OpenAI(api_key=api_key, base_url=base_url)
else:
self.client = OpenAI(api_key=api_key)
self.local = False
self.config_pattern_directory = config_directory
self.pattern = pattern
@ -426,7 +431,7 @@ class Setup:
self.claudeList = ['claude-3-opus-20240229']
load_dotenv(self.env_file)
try:
openaiapikey = os.environ["OPENAI_API_KEY"]
openaiapikey = os.getenv("OPENAI_API_KEY")|''
self.openaiapi_key = openaiapikey
except:
pass
@ -482,7 +487,7 @@ class Setup:
api_key = api_key.strip()
if not os.path.exists(self.env_file) and api_key:
with open(self.env_file, "w") as f:
f.write(f"OPENAI_API_KEY={api_key}\n")
f.write(f'OPENAI_API_KEY="{api_key}"\n')
print(f"OpenAI API key set to {api_key}")
elif api_key:
# erase the line OPENAI_API_KEY=key and write the new key
@ -492,8 +497,36 @@ class Setup:
for line in lines:
if "OPENAI_API_KEY" not in line:
f.write(line)
f.write(f"OPENAI_API_KEY={api_key}\n")
f.write(f'OPENAI_API_KEY="{api_key}"\n')
def api_base_url(self, api_base_url):
""" Set the OpenAI API base URL in the environment file.
Args:
api_base_url (str): The API base URL to be set.
Returns:
None
Raises:
OSError: If the environment file does not exist or cannot be accessed.
"""
api_base_url = api_base_url.strip()
if not api_base_url:
api_base_url = "https://api.openai.com/v1/"
if os.path.exists(self.env_file) and api_base_url:
with open(self.env_file, "r") as f:
lines = f.readlines()
with open(self.env_file, "w") as f:
for line in lines:
if "OPENAI_BASE_URL" not in line:
f.write(line)
f.write(f'OPENAI_BASE_URL="{api_base_url}"')
elif api_base_url:
with open(self.env_file, "w") as f:
f.write(f'OPENAI_BASE_URL="{api_base_url}"')
def claude_key(self, claude_key):
""" Set the Claude API key in the environment file.
@ -709,7 +742,11 @@ class Setup:
print("Welcome to Fabric. Let's get started.")
apikey = input(
"Please enter your OpenAI API key. If you do not have one or if you have already entered it, press enter.\n")
self.api_key(apikey)
self.api_key(apikey.strip())
apiBaseURL = input(
"Please enter the OpenAI API Base URL. If you want to use the default, press enter.\n")
self.api_base_url(apiBaseURL.strip())
print("Please enter your claude API key. If you do not have one, or if you have already entered it, press enter.\n")
claudekey = input()
self.claude_key(claudekey)

6
installer/client/gui/chatgpt.js

@ -12,7 +12,11 @@ function getOpenAIClient() {
"The OPENAI_API_KEY environment variable is missing or empty."
);
}
return new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
if(!process.env.OPENAI_BASE_URL){
return new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
}else{
return new OpenAI({ apiKey: process.env.OPENAI_API_KEY, baseURL: process.env.OPENAI_BASE_URL});
}
}
async function queryOpenAI(system, user, callback) {

10
installer/client/gui/index.html

@ -59,8 +59,16 @@
placeholder="Enter OpenAI API Key"
class="form-control"
/>
<button id="saveApiKey" class="btn btn-primary">Save API Key</button>
<input
type="text"
id="apiBaseURLInput"
placeholder="Enter OpenAI baseURL"
value="https://api.openai.com/v1"
class="form-control"
/>
<button id="saveApiConfig" class="btn btn-primary">Update OpenAI configuration</button>
</div>
<div class="container hidden" id="lastQueryContainer"></div>
<div class="container hidden" id="responseContainer"></div>
</main>
<script src="static/js/jquery-3.0.0.slim.min.js"></script>

52
installer/client/gui/main.js

@ -29,9 +29,9 @@ function promptUserForApiKey() {
});
// Handle the API key submission from the prompt window
ipcMain.on("submit-api-key", (event, apiKey) => {
if (apiKey) {
saveApiKey(apiKey);
ipcMain.on("submit-api-config", (event, apiKey, apiBaseURL) => {
if ((apiKey) && (apiBaseURL)) {
saveApiConfig(apiKey, apiBaseURL);
promptWindow.close();
createWindow(); // Proceed to create the main window
} else {
@ -45,7 +45,7 @@ function loadApiKey() {
const configPath = path.join(os.homedir(), ".config", "fabric", ".env");
if (fs.existsSync(configPath)) {
const envContents = fs.readFileSync(configPath, { encoding: "utf8" });
const matches = envContents.match(/^OPENAI_API_KEY=(.*)$/m);
const matches = envContents.match(/^OPENAI_API_KEY="(.*)"$/m);
if (matches && matches[1]) {
return matches[1];
}
@ -53,7 +53,19 @@ function loadApiKey() {
return null;
}
function saveApiKey(apiKey) {
function loadBaseURL() {
const configPath = path.join(os.homedir(), ".config", "fabric", ".env");
if (fs.existsSync(configPath)) {
const envContents = fs.readFileSync(configPath, { encoding: "utf8" });
const matches = envContents.match(/^OPENAI_BASE_URL="(.*)"$/m);
if (matches && matches[1]) {
return matches[1];
}
}
return null;
}
function saveApiConfig(apiKey, apiBaseURL) {
const configPath = path.join(os.homedir(), ".config", "fabric");
const envFilePath = path.join(configPath, ".env");
@ -61,8 +73,10 @@ function saveApiKey(apiKey) {
fs.mkdirSync(configPath, { recursive: true });
}
fs.writeFileSync(envFilePath, `OPENAI_API_KEY=${apiKey}`);
fs.writeFileSync(envFilePath, `OPENAI_API_KEY="${apiKey}"\n`);
fs.appendFileSync(envFilePath, `OPENAI_BASE_URL="${apiBaseURL}"\n`);
process.env.OPENAI_API_KEY = apiKey; // Set for current session
process.env.OPENAI_BASE_URL = apiBaseURL; // Set for current session
}
function ensureFabricFoldersExist() {
@ -127,7 +141,7 @@ async function downloadAndUpdatePatterns(patternsPath) {
}
}
function checkApiKeyExists() {
function checkEnvExists() {
const configPath = path.join(os.homedir(), ".config", "fabric", ".env");
return fs.existsSync(configPath);
}
@ -245,21 +259,13 @@ ipcMain.handle("get-pattern-content", async (event, patternName) => {
}
});
ipcMain.handle("save-api-key", async (event, apiKey) => {
ipcMain.handle("save-api-config", async (event, apiKey, apiBaseURL) => {
try {
const configPath = path.join(os.homedir(), ".config", "fabric");
if (!fs.existsSync(configPath)) {
fs.mkdirSync(configPath, { recursive: true });
}
const envFilePath = path.join(configPath, ".env");
fs.writeFileSync(envFilePath, `OPENAI_API_KEY=${apiKey}`);
process.env.OPENAI_API_KEY = apiKey;
return "API Key saved successfully.";
saveApiConfig(apiKey, apiBaseURL);
return "API configuration saved successfully.";
} catch (error) {
console.error("Error saving API key:", error);
throw new Error("Failed to save API Key.");
console.error("Error saving API configuration:", error);
throw new Error("Failed to save API Key and Base URL.");
}
});
@ -276,10 +282,10 @@ app.whenReady().then(async () => {
createWindow(); // Create the application window
// After window creation, check if the API key exists
if (!checkApiKeyExists()) {
console.log("API key is missing. Prompting user to input API key.");
if (!checkApiEnvExists()) {
console.log("API environment is missing. Prompting user to input API key and base URL.");
// Optionally, directly invoke a function here to show a prompt in the renderer process
win.webContents.send("request-api-key");
win.webContents.send("request-api-config");
}
} catch (error) {
console.error("Failed to initialize fabric folders:", error);

19
installer/client/gui/static/js/index.js

@ -2,12 +2,14 @@ document.addEventListener("DOMContentLoaded", async function () {
const patternSelector = document.getElementById("patternSelector");
const userInput = document.getElementById("userInput");
const submitButton = document.getElementById("submit");
const lastQueryContainer = document.getElementById("lastQueryContainer");
const responseContainer = document.getElementById("responseContainer");
const themeChanger = document.getElementById("themeChanger");
const configButton = document.getElementById("configButton");
const configSection = document.getElementById("configSection");
const saveApiKeyButton = document.getElementById("saveApiKey");
const saveApiConfigButton = document.getElementById("saveApiConfig");
const apiKeyInput = document.getElementById("apiKeyInput");
const apiBaseURLInput = document.getElementById("apiBaseURLInput");
const originalPlaceholder = userInput.placeholder;
const updatePatternsButton = document.getElementById("updatePatternsButton");
const copyButton = document.createElement("button");
@ -16,7 +18,7 @@ document.addEventListener("DOMContentLoaded", async function () {
console.log("Patterns are ready. Refreshing the pattern list.");
loadPatterns();
});
window.electronAPI.on("request-api-key", () => {
window.electronAPI.on("request-api-config", () => {
// Show the API key input section or modal to the user
configSection.classList.remove("hidden"); // Assuming 'configSection' is your API key input area
});
@ -56,6 +58,8 @@ document.addEventListener("DOMContentLoaded", async function () {
}
async function submitQuery(userInputValue) {
lastQueryContainer.textContent = htmlToPlainText(userInputValue);
lastQueryContainer.classList.remove("hidden");
userInput.value = ""; // Clear the input after submitting
systemCommand = await window.electronAPI.invoke(
"get-pattern-content",
@ -188,19 +192,20 @@ document.addEventListener("DOMContentLoaded", async function () {
});
// Save API Key button click handler
saveApiKeyButton.addEventListener("click", () => {
saveApiConfigButton.addEventListener("click", () => {
const apiKey = apiKeyInput.value;
const apiBaseURL = apiBaseURLInput.value;
window.electronAPI
.invoke("save-api-key", apiKey)
.invoke("save-api-config", apiKey, apiBaseURL)
.then(() => {
alert("API Key saved successfully.");
alert("API Configuration saved successfully.");
// Optionally hide the config section and clear the input after saving
configSection.classList.add("hidden");
apiKeyInput.value = "";
})
.catch((err) => {
console.error("Error saving API key:", err);
alert("Failed to save API Key.");
console.error("Error saving API configuration:", err);
alert("Failed to save API configurationy.");
});
});

1
testmessage.txt

@ -0,0 +1 @@
hi
Loading…
Cancel
Save