1
0
mirror of https://github.com/typemill/typemill.git synced 2025-07-25 00:02:28 +02:00

fix api call

This commit is contained in:
trendschau
2025-04-02 20:45:48 +02:00
parent c27b024fe3
commit 86b5fd432a
4 changed files with 260 additions and 16 deletions

2
cache/timer.yaml vendored
View File

@@ -1 +1 @@
licenseupdate: 1743531622
licenseupdate: 1743542694

View File

@@ -31,7 +31,7 @@ class ApiCalls
return $this->makeFileGetContentsCall($url, 'GET', null, $authHeader);
}
private function makeCurlCall($url, $method, $data = false, $customHeader = '')
private function makeCurlCall($url, $method, $data = false, $customHeaders = '')
{
$this->error = null;
@@ -39,7 +39,7 @@ class ApiCalls
"Content-Type: application/json",
];
$headers = $this->addCustomHeader($customHeader);
$headers = $this->addCustomHeaders($headers, $customHeaders);
$curl = curl_init($url);
if (defined('CURLSSLOPT_NATIVE_CA') && version_compare(curl_version()['version'], '7.71', '>='))
@@ -75,7 +75,7 @@ class ApiCalls
return $response;
}
private function makeFileGetContentsCall($url, $method, $data = null, $customHeader = '')
private function makeFileGetContentsCall($url, $method, $data = null, $customHeaders = '')
{
$this->error = null;
@@ -83,7 +83,7 @@ class ApiCalls
"Content-Type: application/json"
];
$headers = $this->addCustomHeader($headers, $customHeader);
$headers = $this->addCustomHeader($headers, $customHeaders);
$options = [
'http' => [
@@ -128,23 +128,28 @@ class ApiCalls
return $response;
}
private function addCustomHeader(array $header, $customHeader = '')
private function addCustomHeaders($headers, $customHeaders = '')
{
if(!empty($customHeader))
if(!is_array($headers))
{
if(is_array($customHeader))
return false;
}
if(!empty($customHeaders))
{
if(is_array($customHeaders))
{
foreach($customHeader as $cHeader)
foreach($customHeaders as $cHeader)
{
$header[] = $cHeader;
$headers[] = $cHeader;
}
}
elseif(is_string($customHeader))
elseif(is_string($customHeaders))
{
$header[] = $customHeader;
$headers[] = $customHeaders;
}
}
return $header;
return $headers;
}
}

View File

@@ -130,9 +130,9 @@ const kixote = Vue.createApp({
tabs: [
"Admin",
"Generate",
"SEO",
/* "Automate",
"Translate",
"SEO",
"RAG" */
],
icons: {
@@ -1005,6 +1005,246 @@ kixote.component('tab-generate', {
}
})
kixote.component('tab-seo', {
props: ['content', 'item', 'labels', 'urlinfo', 'settings', 'kixoteSettings', 'settingsSaved', 'aiservice', 'useragreement', 'tokenstats'],
data: function () {
return {
article: '',
};
},
template: `<section class="dark:bg-stone-700 dark:text-stone-200">
<div v-if="!aiservice" class="p-8 mt-4 w-full">
<div class="bg-stone-700 p-8 border border-stone-500 rounded-lg shadow-md">
<h2 class="text-xl font-bold text-white mb-4">Your AI Assistant for Typemill</h2>
<p class="text-stone-300 mb-4">
To get started with AI-powered assistance, go to <strong class="text-white">System Settings</strong>, open the <strong class="text-white">AI</strong> tab, and follow these steps:
</p>
<ol class="list-decimal list-inside text-stone-300 space-y-2">
<li>Select an AI service.</li>
<li>Choose a model.</li>
<li>Enter your API key.</li>
</ol>
<p class="text-stone-300 mt-4">Once set up, you can start using AI assistance right away!</p>
</div>
</div>
<div v-else-if="content">
<div v-if="!useragreement" class="p-8 mt-4 inline-block w-full">
<div class="bg-stone-700 p-8 border border-stone-500">
<div class="w-full mt-5 mb-5">
<div class="block mb-1 font-medium">Activate {{aiservice}}</div>
<label class="flex items-start mb-2 mt-2">
<input
type = "checkbox"
class = "w-6 h-6 border-stone-300 bg-stone-200"
value = "chatgpt"
@change = "agreeTo(aiservice)"
>
<span class="ml-2 text-sm">
Activate {{aiservice}} to start using AI assistance. By enabling this service, you agree to the terms and conditions of {{aiservice}}.
Your prompts and article content will be sent to {{aiservice}} to generate responses.
You can disable {{aiservice}} at any time in your user profile.
</span>
</label>
</div>
</div>
</div>
<div v-else>
<!-- PROMPT INPUT -->
<div v-if="promptError" class="w-full px-8 py-1 bg-rose-500 text-white">{{ promptError }}</div>
<div class="w-full bg-stone-600 px-8 py-2">
<div class="flex items-start">
<span class="text-teal-300 mr-1">Ki></span>
<textarea
v-model.trim = "prompt"
ref = "prompteditor"
class = "flex-grow bg-stone-600 focus:outline-none border-0 caret-white"
placeholder = "Prompt..."
@keydown.enter = "handleKeydown"
@input = "resizePromptEditor"
></textarea>
<button
class = "text-teal-300 px-2"
@click = "submitPrompt"
>submit
</button>
<span class="px-1 text-stone-700">|</span>
<button
class = "text-teal-300 px-2"
@click = "exit"
>exit
</button>
</div>
</div>
</div>
</div>
</div>
<div v-else class="p-8 mt-4 inline-block w-full">
<p class="text-center bg-stone-700 p-8 border border-stone-500">Content Generation only works on content pages. You are currently in the settings area.</p>
</div>
</section>`,
mounted: function()
{
this.initAutosize();
if(this.versions.length == 0)
{
this.initializeContent()
}
},
watch: {
currentTab(newTab, oldTab) {
if (newTab === 'article')
{
this.$nextTick(() => {
this.initAutosize(); // Trigger the resizing when switching back to the article tab
});
}
}
},
methods: {
initAutosize()
{
let kieditor = this.$refs["kieditor"];
let prompteditor = this.$refs["prompteditor"];
if (kieditor)
{
autosize(kieditor);
}
if (prompteditor)
{
autosize(prompteditor);
}
},
agreeTo(aiservice)
{
var self = this;
tmaxios.post('/api/v1/agreetoaiservice',{
'aiservice': aiservice
})
.then(function (response)
{
eventBus.$emit('agreetoservice');
self.$nextTick(() => {
self.initAutosize();
});
})
},
initializeContent()
{
let markdown = '';
for(block in this.content)
{
markdown += this.content[block].markdown + '\n\n';
}
this.originalmd = markdown;
this.versions.push(markdown);
this.resizeAiEditor();
},
resizeAiEditor()
{
this.$nextTick(() => {
let kieditor = this.$refs["kieditor"];
if (kieditor)
{
autosize.update(kieditor);
}
});
},
resizePromptEditor()
{
this.$nextTick(() => {
let prompteditor = this.$refs["prompteditor"];
if (prompteditor)
{
autosize.update(prompteditor);
}
});
},
submitPrompt()
{
this.promptError = false;
var self = this;
eventBus.$emit('switchLoading');
tmaxios.post('/api/v1/prompt',{
'prompt': this.prompt,
'article': this.versions[this.activeversion]
})
.then(function (response)
{
eventBus.$emit('switchLoading');
if (response.data.message === 'Success')
{
let answer = response.data.answer;
answer = answer.replace(/<\/?focus>/g, '');
self.versions.push(answer);
self.activeversion = self.versions.length-1;
self.prompt = '';
self.resizePromptEditor();
self.resizeAiEditor();
}
})
.catch(function (error)
{
eventBus.$emit('switchLoading');
if(error.response)
{
self.disabled = false;
self.promptError = handleErrorMessage(error);
self.licensemessage = error.response.data.message;
if(error.response.data.errors !== undefined)
{
self.promptError = error.response.data.errors;
}
}
});
},
handleKeydown(event)
{
if (event.key === 'Enter' && !event.shiftKey)
{
event.preventDefault();
this.submitPrompt();
}
else if (event.key === 'Enter' && event.shiftKey)
{
// Allow line break
const textarea = event.target;
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
textarea.value = textarea.value.slice(0, start) + '\n' + textarea.value.slice(end);
textarea.selectionStart = textarea.selectionEnd = start + 1;
let prompteditor = this.$refs["prompteditor"];
autosize.update(prompteditor);
event.preventDefault();
}
},
exit()
{
eventBus.$emit('kiExit');
},
}
})
// publish tree
// unpublish tree
// load page

View File

@@ -53,8 +53,7 @@ const app = Vue.createApp({
const componentName = 'tab-' + this.currentTab.toLowerCase();
if (this.$root.$options.components && this.$root.$options.components[componentName])
if(this.$root.$.appContext.components[componentName])
{
return componentName;
}