@mulmochat-plugin/generate-image 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,11 @@
5
5
  * These types are plugin-agnostic and can be used by any plugin implementation.
6
6
  */
7
7
  import type { Component } from "vue";
8
+ /**
9
+ * Backend types that plugins can declare they use.
10
+ * App layer manages actual provider/model settings for each type.
11
+ */
12
+ export type BackendType = "textLLM" | "imageGen" | "audio" | "search" | "browse" | "map" | "mulmocast";
8
13
  /**
9
14
  * Context passed to plugin execute function
10
15
  */
@@ -127,4 +132,6 @@ export interface ToolPlugin<T = unknown, J = unknown, A extends object = object>
127
132
  config?: ToolPluginConfig;
128
133
  /** Optional sample arguments for testing */
129
134
  samples?: ToolSample[];
135
+ /** Backend types this plugin uses (e.g., ["textLLM", "imageGen"]) */
136
+ backends?: BackendType[];
130
137
  }
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),m=require("@mulmochat-plugin/ui-image"),s="generateImage",c={type:"function",name:s,description:"Generate an image based on the prompt and display it on the screen. Be descriptive and specify the concrete details of the images in the prompt. Each call generates one image.",parameters:{type:"object",properties:{prompt:{type:"string",description:"A detailed prompt describing the image to generate"}},required:["prompt"]}},f=[{name:"Sunset Beach",args:{imageData:"https://picsum.photos/id/28/800/600",prompt:"A beautiful sunset over a calm ocean beach with palm trees"}},{name:"Mountain Lake",args:{imageData:"https://picsum.photos/id/29/800/600",prompt:"A serene mountain lake surrounded by pine trees and snow-capped peaks"}},{name:"City Skyline",args:{imageData:"https://picsum.photos/id/43/800/600",prompt:"A modern city skyline at night with glowing skyscrapers"}},{name:"Forest Path",args:{imageData:"https://picsum.photos/id/15/800/600",prompt:"A winding path through an enchanted forest with sunlight filtering through the leaves"}}],v=e.defineComponent({__name:"View",props:{selectedResult:{},sendTextMessage:{type:Function}},emits:["updateResult"],setup(a){const l=a,n=e.ref(null);return e.watch(()=>l.selectedResult,i=>{i?.toolName===s&&i.data&&(n.value=i)},{immediate:!0,deep:!0}),(i,o)=>n.value?(e.openBlock(),e.createBlock(e.unref(m.ImageView),{key:0,selectedResult:n.value},null,8,["selectedResult"])):e.createCommentVNode("",!0)}}),y=e.defineComponent({__name:"Preview",props:{result:{}},setup(a){return(l,n)=>(e.openBlock(),e.createBlock(e.unref(m.ImagePreview),{result:a.result},null,8,["result"]))}}),h={class:"space-y-4"},b=["value"],k={key:0},M=["value"],E={key:1},N=["value"],x=["value"],V=e.defineComponent({__name:"ImageGenerationConfig",props:{value:{}},emits:["update:value"],setup(a,{emit:l}){const n=a,i=l,o=e.computed(()=>typeof n.value=="string"?{backend:n.value,styleModifier:"",geminiModel:"gemini-2.5-flash-image",openaiModel:"gpt-image-1"}:{...n.value,geminiModel:n.value.geminiModel||"gemini-2.5-flash-image",openaiModel:n.value.openaiModel||"gpt-image-1"}),u=r=>{const t=r.target.value;i("update:value",{...o.value,backend:t})},d=r=>{const t=r.target.value;i("update:value",{...o.value,styleModifier:t})},p=r=>{const t=r.target.value;i("update:value",{...o.value,geminiModel:t})},g=r=>{const t=r.target.value;i("update:value",{...o.value,openaiModel:t})};return(r,t)=>(e.openBlock(),e.createElementBlock("div",h,[e.createElementVNode("div",null,[t[1]||(t[1]=e.createElementVNode("label",{class:"block text-sm font-medium text-gray-700 mb-2"}," Image Generation Backend ",-1)),e.createElementVNode("select",{value:o.value.backend,onChange:u,class:"w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"},[...t[0]||(t[0]=[e.createElementVNode("option",{value:"gemini"},"Google Gemini",-1),e.createElementVNode("option",{value:"openai"},"OpenAI",-1),e.createElementVNode("option",{value:"comfyui"},"ComfyUI (Local)",-1)])],40,b),t[2]||(t[2]=e.createElementVNode("p",{class:"text-xs text-gray-500 mt-1"}," Choose between cloud-based Gemini or OpenAI, or a local ComfyUI workflow for image generation. ",-1))]),o.value.backend==="gemini"?(e.openBlock(),e.createElementBlock("div",k,[t[4]||(t[4]=e.createElementVNode("label",{class:"block text-sm font-medium text-gray-700 mb-2"}," Gemini Model ",-1)),e.createElementVNode("select",{value:o.value.geminiModel||"gemini-2.5-flash-image",onChange:p,class:"w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"},[...t[3]||(t[3]=[e.createElementVNode("option",{value:"gemini-2.5-flash-image"},"Gemini 2.5 Flash Image",-1),e.createElementVNode("option",{value:"gemini-3-pro-image-preview"}," Gemini 3 Pro Image (Preview) ",-1)])],40,M),t[5]||(t[5]=e.createElementVNode("p",{class:"text-xs text-gray-500 mt-1"}," Select which Gemini model to use for image generation. ",-1))])):e.createCommentVNode("",!0),o.value.backend==="openai"?(e.openBlock(),e.createElementBlock("div",E,[t[7]||(t[7]=e.createElementVNode("label",{class:"block text-sm font-medium text-gray-700 mb-2"}," OpenAI Model ",-1)),e.createElementVNode("select",{value:o.value.openaiModel||"gpt-image-1",onChange:g,class:"w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"},[...t[6]||(t[6]=[e.createElementVNode("option",{value:"gpt-image-1"},"GPT Image 1",-1),e.createElementVNode("option",{value:"gpt-image-1.5"},"GPT Image 1.5",-1),e.createElementVNode("option",{value:"gpt-image-1-mini"},"GPT Image 1 Mini",-1)])],40,N),t[8]||(t[8]=e.createElementVNode("p",{class:"text-xs text-gray-500 mt-1"}," Select which OpenAI image model to use. ",-1))])):e.createCommentVNode("",!0),e.createElementVNode("div",null,[t[9]||(t[9]=e.createElementVNode("label",{class:"block text-sm font-medium text-gray-700 mb-2"}," Additional Style Modifier ",-1)),e.createElementVNode("input",{type:"text",value:o.value.styleModifier||"",onInput:d,placeholder:"e.g., ghibli-style anime, oil painting, cyberpunk",class:"w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"},null,40,x),t[10]||(t[10]=e.createElementVNode("p",{class:"text-xs text-gray-500 mt-1"}," This style will be automatically appended to all image generation prompts. Leave empty for no additional styling. ",-1))])]))}}),I=async(a,l)=>{const{prompt:n}=l;return a.app?.generateImage?a.app.generateImage(a,n):{message:"generateImage function not available"}};function w(a,l,n){return{toolName:s,data:{imageData:a,prompt:n},message:"",title:l}}const C={toolDefinition:c,execute:I,generatingMessage:"Generating image...",isEnabled:()=>!0,viewComponent:v,previewComponent:y,fileUpload:{acceptedTypes:["image/png","image/jpeg"],handleUpload:w},systemPrompt:`When you are talking about places, objects, people, movies, books and other things, you MUST use the ${s} API to draw pictures to make the conversation more engaging.`,config:{key:"imageGenerationBackend",defaultValue:{backend:"gemini",styleModifier:"",geminiModel:"gemini-2.5-flash-image",openaiModel:"gpt-image-1"},component:V},samples:f},G={plugin:C};exports.default=G;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("vue"),r=require("@mulmochat-plugin/ui-image"),o="generateImage",i={type:"function",name:o,description:"Generate an image based on the prompt and display it on the screen. Be descriptive and specify the concrete details of the images in the prompt. Each call generates one image.",parameters:{type:"object",properties:{prompt:{type:"string",description:"A detailed prompt describing the image to generate"}},required:["prompt"]}},p=[{name:"Sunset Beach",args:{imageData:"https://picsum.photos/id/28/800/600",prompt:"A beautiful sunset over a calm ocean beach with palm trees"}},{name:"Mountain Lake",args:{imageData:"https://picsum.photos/id/29/800/600",prompt:"A serene mountain lake surrounded by pine trees and snow-capped peaks"}},{name:"City Skyline",args:{imageData:"https://picsum.photos/id/43/800/600",prompt:"A modern city skyline at night with glowing skyscrapers"}},{name:"Forest Path",args:{imageData:"https://picsum.photos/id/15/800/600",prompt:"A winding path through an enchanted forest with sunlight filtering through the leaves"}}],c=e.defineComponent({__name:"View",props:{selectedResult:{},sendTextMessage:{type:Function}},emits:["updateResult"],setup(t){const n=t,a=e.ref(null);return e.watch(()=>n.selectedResult,s=>{s?.toolName===o&&s.data&&(a.value=s)},{immediate:!0,deep:!0}),(s,h)=>a.value?(e.openBlock(),e.createBlock(e.unref(r.ImageView),{key:0,selectedResult:a.value},null,8,["selectedResult"])):e.createCommentVNode("",!0)}}),m=e.defineComponent({__name:"Preview",props:{result:{}},setup(t){return(n,a)=>(e.openBlock(),e.createBlock(e.unref(r.ImagePreview),{result:t.result},null,8,["result"]))}}),u=async(t,n)=>{const{prompt:a}=n;return t.app?.generateImage?t.app.generateImage(a):{message:"generateImage function not available"}};function l(t,n,a){return{toolName:o,data:{imageData:t,prompt:a},message:"",title:n}}const g={toolDefinition:i,execute:u,generatingMessage:"Generating image...",isEnabled:()=>!0,viewComponent:c,previewComponent:m,fileUpload:{acceptedTypes:["image/png","image/jpeg"],handleUpload:l},systemPrompt:`When you are talking about places, objects, people, movies, books and other things, you MUST use the ${o} API to draw pictures to make the conversation more engaging.`,backends:["imageGen"],samples:p},d={plugin:g};exports.default=d;
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { defineComponent as g, ref as b, watch as k, createBlock as d, createCommentVNode as p, openBlock as r, unref as c, computed as x, createElementBlock as m, createElementVNode as t } from "vue";
2
- import { ImageView as M, ImagePreview as I } from "@mulmochat-plugin/ui-image";
3
- const u = "generateImage", w = {
1
+ import { defineComponent as o, ref as m, watch as c, createBlock as r, createCommentVNode as u, openBlock as i, unref as p } from "vue";
2
+ import { ImageView as g, ImagePreview as l } from "@mulmochat-plugin/ui-image";
3
+ const s = "generateImage", d = {
4
4
  type: "function",
5
- name: u,
5
+ name: s,
6
6
  description: "Generate an image based on the prompt and display it on the screen. Be descriptive and specify the concrete details of the images in the prompt. Each call generates one image.",
7
7
  parameters: {
8
8
  type: "object",
@@ -14,7 +14,7 @@ const u = "generateImage", w = {
14
14
  },
15
15
  required: ["prompt"]
16
16
  }
17
- }, C = [
17
+ }, h = [
18
18
  {
19
19
  name: "Sunset Beach",
20
20
  args: {
@@ -43,164 +43,62 @@ const u = "generateImage", w = {
43
43
  prompt: "A winding path through an enchanted forest with sunlight filtering through the leaves"
44
44
  }
45
45
  }
46
- ], G = /* @__PURE__ */ g({
46
+ ], f = /* @__PURE__ */ o({
47
47
  __name: "View",
48
48
  props: {
49
49
  selectedResult: {},
50
50
  sendTextMessage: { type: Function }
51
51
  },
52
52
  emits: ["updateResult"],
53
- setup(n) {
54
- const l = n, a = b(null);
55
- return k(
56
- () => l.selectedResult,
57
- (i) => {
58
- i?.toolName === u && i.data && (a.value = i);
53
+ setup(e) {
54
+ const a = e, t = m(null);
55
+ return c(
56
+ () => a.selectedResult,
57
+ (n) => {
58
+ n?.toolName === s && n.data && (t.value = n);
59
59
  },
60
60
  { immediate: !0, deep: !0 }
61
- ), (i, o) => a.value ? (r(), d(c(M), {
61
+ ), (n, b) => t.value ? (i(), r(p(g), {
62
62
  key: 0,
63
- selectedResult: a.value
64
- }, null, 8, ["selectedResult"])) : p("", !0);
63
+ selectedResult: t.value
64
+ }, null, 8, ["selectedResult"])) : u("", !0);
65
65
  }
66
- }), A = /* @__PURE__ */ g({
66
+ }), y = /* @__PURE__ */ o({
67
67
  __name: "Preview",
68
68
  props: {
69
69
  result: {}
70
70
  },
71
- setup(n) {
72
- return (l, a) => (r(), d(c(I), { result: n.result }, null, 8, ["result"]));
71
+ setup(e) {
72
+ return (a, t) => (i(), r(p(l), { result: e.result }, null, 8, ["result"]));
73
73
  }
74
- }), _ = { class: "space-y-4" }, P = ["value"], O = { key: 0 }, T = ["value"], S = { key: 1 }, B = ["value"], E = ["value"], N = /* @__PURE__ */ g({
75
- __name: "ImageGenerationConfig",
76
- props: {
77
- value: {}
78
- },
79
- emits: ["update:value"],
80
- setup(n, { emit: l }) {
81
- const a = n, i = l, o = x(() => typeof a.value == "string" ? {
82
- backend: a.value,
83
- styleModifier: "",
84
- geminiModel: "gemini-2.5-flash-image",
85
- openaiModel: "gpt-image-1"
86
- } : {
87
- ...a.value,
88
- geminiModel: a.value.geminiModel || "gemini-2.5-flash-image",
89
- openaiModel: a.value.openaiModel || "gpt-image-1"
90
- }), f = (s) => {
91
- const e = s.target.value;
92
- i("update:value", {
93
- ...o.value,
94
- backend: e
95
- });
96
- }, v = (s) => {
97
- const e = s.target.value;
98
- i("update:value", {
99
- ...o.value,
100
- styleModifier: e
101
- });
102
- }, y = (s) => {
103
- const e = s.target.value;
104
- i("update:value", {
105
- ...o.value,
106
- geminiModel: e
107
- });
108
- }, h = (s) => {
109
- const e = s.target.value;
110
- i("update:value", {
111
- ...o.value,
112
- openaiModel: e
113
- });
114
- };
115
- return (s, e) => (r(), m("div", _, [
116
- t("div", null, [
117
- e[1] || (e[1] = t("label", { class: "block text-sm font-medium text-gray-700 mb-2" }, " Image Generation Backend ", -1)),
118
- t("select", {
119
- value: o.value.backend,
120
- onChange: f,
121
- class: "w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
122
- }, [...e[0] || (e[0] = [
123
- t("option", { value: "gemini" }, "Google Gemini", -1),
124
- t("option", { value: "openai" }, "OpenAI", -1),
125
- t("option", { value: "comfyui" }, "ComfyUI (Local)", -1)
126
- ])], 40, P),
127
- e[2] || (e[2] = t("p", { class: "text-xs text-gray-500 mt-1" }, " Choose between cloud-based Gemini or OpenAI, or a local ComfyUI workflow for image generation. ", -1))
128
- ]),
129
- o.value.backend === "gemini" ? (r(), m("div", O, [
130
- e[4] || (e[4] = t("label", { class: "block text-sm font-medium text-gray-700 mb-2" }, " Gemini Model ", -1)),
131
- t("select", {
132
- value: o.value.geminiModel || "gemini-2.5-flash-image",
133
- onChange: y,
134
- class: "w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
135
- }, [...e[3] || (e[3] = [
136
- t("option", { value: "gemini-2.5-flash-image" }, "Gemini 2.5 Flash Image", -1),
137
- t("option", { value: "gemini-3-pro-image-preview" }, " Gemini 3 Pro Image (Preview) ", -1)
138
- ])], 40, T),
139
- e[5] || (e[5] = t("p", { class: "text-xs text-gray-500 mt-1" }, " Select which Gemini model to use for image generation. ", -1))
140
- ])) : p("", !0),
141
- o.value.backend === "openai" ? (r(), m("div", S, [
142
- e[7] || (e[7] = t("label", { class: "block text-sm font-medium text-gray-700 mb-2" }, " OpenAI Model ", -1)),
143
- t("select", {
144
- value: o.value.openaiModel || "gpt-image-1",
145
- onChange: h,
146
- class: "w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
147
- }, [...e[6] || (e[6] = [
148
- t("option", { value: "gpt-image-1" }, "GPT Image 1", -1),
149
- t("option", { value: "gpt-image-1.5" }, "GPT Image 1.5", -1),
150
- t("option", { value: "gpt-image-1-mini" }, "GPT Image 1 Mini", -1)
151
- ])], 40, B),
152
- e[8] || (e[8] = t("p", { class: "text-xs text-gray-500 mt-1" }, " Select which OpenAI image model to use. ", -1))
153
- ])) : p("", !0),
154
- t("div", null, [
155
- e[9] || (e[9] = t("label", { class: "block text-sm font-medium text-gray-700 mb-2" }, " Additional Style Modifier ", -1)),
156
- t("input", {
157
- type: "text",
158
- value: o.value.styleModifier || "",
159
- onInput: v,
160
- placeholder: "e.g., ghibli-style anime, oil painting, cyberpunk",
161
- class: "w-full border border-gray-300 rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
162
- }, null, 40, E),
163
- e[10] || (e[10] = t("p", { class: "text-xs text-gray-500 mt-1" }, " This style will be automatically appended to all image generation prompts. Leave empty for no additional styling. ", -1))
164
- ])
165
- ]));
166
- }
167
- }), D = async (n, l) => {
168
- const { prompt: a } = l;
169
- return n.app?.generateImage ? n.app.generateImage(n, a) : { message: "generateImage function not available" };
74
+ }), _ = async (e, a) => {
75
+ const { prompt: t } = a;
76
+ return e.app?.generateImage ? e.app.generateImage(t) : { message: "generateImage function not available" };
170
77
  };
171
- function L(n, l, a) {
78
+ function k(e, a, t) {
172
79
  return {
173
- toolName: u,
174
- data: { imageData: n, prompt: a },
80
+ toolName: s,
81
+ data: { imageData: e, prompt: t },
175
82
  message: "",
176
- title: l
83
+ title: a
177
84
  };
178
85
  }
179
- const U = {
180
- toolDefinition: w,
181
- execute: D,
86
+ const v = {
87
+ toolDefinition: d,
88
+ execute: _,
182
89
  generatingMessage: "Generating image...",
183
90
  isEnabled: () => !0,
184
- viewComponent: G,
185
- previewComponent: A,
91
+ viewComponent: f,
92
+ previewComponent: y,
186
93
  fileUpload: {
187
94
  acceptedTypes: ["image/png", "image/jpeg"],
188
95
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
189
- handleUpload: L
190
- },
191
- systemPrompt: `When you are talking about places, objects, people, movies, books and other things, you MUST use the ${u} API to draw pictures to make the conversation more engaging.`,
192
- config: {
193
- key: "imageGenerationBackend",
194
- defaultValue: {
195
- backend: "gemini",
196
- styleModifier: "",
197
- geminiModel: "gemini-2.5-flash-image",
198
- openaiModel: "gpt-image-1"
199
- },
200
- component: N
96
+ handleUpload: k
201
97
  },
202
- samples: C
203
- }, F = { plugin: U };
98
+ systemPrompt: `When you are talking about places, objects, people, movies, books and other things, you MUST use the ${s} API to draw pictures to make the conversation more engaging.`,
99
+ backends: ["imageGen"],
100
+ samples: h
101
+ }, A = { plugin: v };
204
102
  export {
205
- F as default
103
+ A as default
206
104
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mulmochat-plugin/generate-image",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Image generation plugin for MulmoChat",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -24,8 +24,8 @@
24
24
  "lint": "eslint src demo"
25
25
  },
26
26
  "peerDependencies": {
27
- "vue": "^3.5.0",
28
- "@mulmochat-plugin/ui-image": "^0.1.0"
27
+ "@mulmochat-plugin/ui-image": "^0.1.0",
28
+ "vue": "^3.5.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@mulmochat-plugin/ui-image": "^0.1.0",
@@ -34,7 +34,7 @@
34
34
  "@typescript-eslint/parser": "^8.53.0",
35
35
  "@vitejs/plugin-vue": "^6.0.3",
36
36
  "eslint": "^9.39.2",
37
- "eslint-plugin-vue": "^10.6.2",
37
+ "eslint-plugin-vue": "^10.7.0",
38
38
  "globals": "^17.0.0",
39
39
  "tailwindcss": "^4.1.18",
40
40
  "typescript": "~5.9.3",
@@ -1,11 +0,0 @@
1
- import type { ImageGenerationConfigValue } from "./types";
2
- type __VLS_Props = {
3
- value: "gemini" | "openai" | "comfyui" | ImageGenerationConfigValue;
4
- };
5
- declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
6
- "update:value": (value: ImageGenerationConfigValue) => any;
7
- }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
8
- "onUpdate:value"?: ((value: ImageGenerationConfigValue) => any) | undefined;
9
- }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
- declare const _default: typeof __VLS_export;
11
- export default _default;