diff --git a/Modules/AI/controller.js b/Modules/AI/controller.js
index 99d3bf75..d787e966 100644
--- a/Modules/AI/controller.js
+++ b/Modules/AI/controller.js
@@ -38,15 +38,31 @@ exports.generatePrompt = (req,res) => {
if (promptsText.toLowerCase().includes(prompt.key.toLowerCase())) {
var parts = promptsText.split(prompt.key);
promptsText = parts.join(prompt.value);
- promptsText = promptsText + promptRes.outputFormat
}
})
+ // Append the schema reminder once after all substitutions.
+ // Previously this lived INSIDE the forEach above, so a
+ // prompt with N substitution keys ended up with N copies
+ // of `outputFormat` glued to the end — wasted tokens and
+ // potentially confusing for the model.
+ promptsText = promptsText + promptRes.outputFormat;
addChat(req.body.uniqueUserId,{role: "user",content: promptsText });
let curlUrl = "https://api.openai.com/v1/chat/completions";
let axiosData = {
"model": config.AI_MODEL,
"messages": [{"role": "user", "content": `${JSON.stringify(promptsText)}`}]
}
+ // Optional per-prompt OpenAI parameters declared on the
+ // prompt entry in utils/aiPrompts.json. Backwards-
+ // compatible: prompts that don't declare these keep the
+ // OpenAI defaults (and the streaming branch keeps its
+ // own hardcoded response_format below).
+ if (promptRes.responseFormat) {
+ axiosData.response_format = promptRes.responseFormat;
+ }
+ if (typeof promptRes.temperature === 'number') {
+ axiosData.temperature = promptRes.temperature;
+ }
const header = {
headers: {
Authorization: `Bearer ${config.AI_API_KEY}`,
diff --git a/frontend/src/locales/en.js b/frontend/src/locales/en.js
index 635d6beb..8ae455ce 100644
--- a/frontend/src/locales/en.js
+++ b/frontend/src/locales/en.js
@@ -1652,6 +1652,41 @@ export default {
ai_not_integrated: "AI is not integrated in your system",
limit_reached: "You have reached your limit",
},
+ AICard: {
+ button_label: "AI Create Card",
+ title: "AI Create Card",
+ prompt_label: "Describe the card you want",
+ prompt_subtitle: "Tell us in plain English what you want to see and AI will assemble a card for you.",
+ prompt_placeholder: "e.g. Show a pie chart of urgent open tasks for the AlianHub project",
+ helper_idle: "Minimum {n} characters",
+ helper_more: "{remaining} more to go",
+ examples_heading: "Try one of these",
+ chip_workload: "Workload by status",
+ chip_workload_prompt: "Pie chart of workload by status",
+ chip_assignee: "Tasks by assignee",
+ chip_assignee_prompt: "Bar chart of tasks grouped by assignee",
+ chip_urgent: "Urgent tasks",
+ chip_urgent_prompt: "List of my urgent open tasks",
+ chip_calendar: "Due-date calendar",
+ chip_calendar_prompt: "Calendar view of upcoming due dates",
+ chip_time: "Time tracking",
+ chip_time_prompt: "Time tracking summary for this week",
+ generate: "Generate",
+ generating: "Generating your card…",
+ preview_heading: "Preview",
+ card_type: "Card type",
+ card_name: "Card name",
+ projects: "Projects",
+ filters: "Filters",
+ add_to_dashboard: "Add to Dashboard",
+ regenerate: "Regenerate",
+ try_again: "Try Again",
+ error_heading: "Couldn't generate a card",
+ error_invalid_json: "The AI response wasn't valid card JSON. Try rephrasing your request.",
+ error_unknown_card: "The AI picked a card type that doesn't exist. Try rephrasing your request.",
+ error_engine: "The AI engine returned an error. Please try again.",
+ fallback_card_name: "AI generated card",
+ },
Toast: {
Your_card_is_expired: "Your card is expired.",
Password_set_new_has_been_successfully:
diff --git a/frontend/src/plugins/dashboard/components/AICardSidebar.vue b/frontend/src/plugins/dashboard/components/AICardSidebar.vue
new file mode 100644
index 00000000..10030f53
--- /dev/null
+++ b/frontend/src/plugins/dashboard/components/AICardSidebar.vue
@@ -0,0 +1,962 @@
+
+ {{ companyUser.dashboardLocked ? $t('Home.unlock') : $t('Home.lock') }}
+
+