1
- import { ref , computed , onMounted } from "vue"
1
+ import { ref , computed , watch , onMounted } from "vue"
2
2
import { useClient } from "@servicestack/vue"
3
3
import { createErrorStatus } from "@servicestack/client"
4
4
import { ActiveAiModels , QueryPrompts , OpenAiChatCompletion } from "dtos"
5
5
6
6
export default {
7
7
template :`
8
8
<div v-if="system">
9
- <button @click="show=!show " type="button" class="-ml-3 bg-white text-gray-600 hover:text-gray-900 group w-full flex items-center pr-2 py-2 text-left text-sm font-medium">
10
- <svg v-if="show" class="text-gray-400 rotate-90 mr-0.5 flex-shrink-0 h-5 w-5 transform group-hover:text-gray-400 transition-colors ease-in-out duration-150" viewBox="0 0 20 20" aria-hidden="true"><path d="M6 6L14 10L6 14V6Z" fill="currentColor"></path></svg>
9
+ <button @click="toggleShow() " type="button" class="-ml-3 bg-white text-gray-600 hover:text-gray-900 group w-full flex items-center pr-2 py-2 text-left text-sm font-medium">
10
+ <svg v-if="prefs. show" class="text-gray-400 rotate-90 mr-0.5 flex-shrink-0 h-5 w-5 transform group-hover:text-gray-400 transition-colors ease-in-out duration-150" viewBox="0 0 20 20" aria-hidden="true"><path d="M6 6L14 10L6 14V6Z" fill="currentColor"></path></svg>
11
11
<svg v-else class="text-gray-300 mr-0.5 flex-shrink-0 h-5 w-5 transform group-hover:text-gray-400 transition-colors ease-in-out duration-150" viewBox="0 0 20 20" aria-hidden="true"><path d="M6 6L14 10L6 14V6Z" fill="currentColor"></path></svg>
12
12
AI Prompt Generator
13
13
</button>
14
- <div v-if="show">
14
+ <div v-if="prefs. show">
15
15
<form class="grid grid-cols-6 gap-4" @submit.prevent="send()" :disabled="!validPrompt">
16
16
<div class="col-span-6 sm:col-span-2">
17
- <TextInput id="subject" v-model="subject" label="subject" placeholder="Use AI to generate image prompts for..." />
17
+ <TextInput id="subject" v-model="prefs. subject" label="subject" placeholder="Use AI to generate image prompts for..." />
18
18
</div>
19
19
<div class="col-span-6 sm:col-span-2">
20
- <Autocomplete id="model" :options="models" v-model="model" label="model"
20
+ <Autocomplete id="model" :options="models" v-model="prefs. model" label="model"
21
21
:match="(x, value) => x.toLowerCase().includes(value.toLowerCase())"
22
+ class="z-20"
22
23
placeholder="Select Model...">
23
24
<template #item="name">
24
25
<div class="flex items-center">
@@ -29,53 +30,57 @@ export default {
29
30
</Autocomplete>
30
31
</div>
31
32
<div class="col-span-6 sm:col-span-1">
32
- <TextInput type="number" id="count" v-model="count" label="count" min="1" />
33
+ <TextInput type="number" id="count" v-model="prefs. count" label="count" min="1" />
33
34
</div>
34
35
<div class="col-span-6 sm:col-span-1 align-bottom">
35
36
<div> </div>
36
37
<PrimaryButton :disabled="!validPrompt">Generate</PrimaryButton>
37
38
</div>
38
39
</form>
39
- <Loading v-if="client.loading.value">Asking {{model}}...</Loading>
40
+ <Loading v-if="client.loading.value">Asking {{prefs. model}}...</Loading>
40
41
<ErrorSummary v-else-if="error" :status="error" />
41
- <div v-else-if="results.length" class="mt-4">
42
- <div v-for="result in results" @click="$emit('selected',result)" class="message mb-2 cursor-pointer rounded-lg inline-flex justify-center rounded-lg text-sm py-3 px-4 bg-gray-50 text-slate-900 ring-1 ring-slate-900/10 hover:bg-white/25 hover:ring-slate-900/15">
42
+ <div v-else-if="prefs. results.length" class="mt-4">
43
+ <div v-for="result in prefs. results" @click="$emit('selected',result)" class="message mb-2 cursor-pointer rounded-lg inline-flex justify-center rounded-lg text-sm py-3 px-4 bg-gray-50 text-slate-900 ring-1 ring-slate-900/10 hover:bg-white/25 hover:ring-slate-900/15">
43
44
{{result}}
44
45
</div>
45
46
</div>
46
47
</div>
47
48
</div>
48
49
` ,
49
- emits :[ 'selected' ] ,
50
+ emits :[ 'save' , ' selected'] ,
50
51
props : {
52
+ thread : Object ,
51
53
promptId : String ,
52
54
systemPrompt : String ,
53
55
} ,
54
- setup ( props ) {
56
+ setup ( props , { emit } ) {
55
57
const client = useClient ( )
56
58
const request = ref ( new OpenAiChatCompletion ( { } ) )
57
59
const system = ref ( props . systemPrompt )
58
- const subject = ref ( '' )
59
60
const defaults = {
60
61
show : false ,
61
- model : 'gemini-flash' ,
62
+ subject : '' ,
63
+ model : '' ,
62
64
count : 3 ,
65
+ results : [ ] ,
63
66
}
64
- const prefsKey = 'img2txt.gen.prefs'
65
- const prefs = JSON . parse ( localStorage . getItem ( prefsKey ) ?? JSON . stringify ( defaults ) )
66
- const show = ref ( prefs . show )
67
- const count = ref ( prefs . count )
68
- const model = ref ( prefs . model )
67
+ const prefs = ref ( Object . assign ( { } , defaults , props . thread ?. generator ) )
69
68
const error = ref ( )
70
69
const models = ref ( [ ] )
71
- const results = ref ( [ ] )
72
- const validPrompt = computed ( ( ) => subject . value && model . value && count . value )
70
+ const validPrompt = computed ( ( ) => prefs . value . subject && prefs . value . model && prefs . value . count )
71
+
72
+ watch ( ( ) => props . thread , ( ) => {
73
+ Object . assign ( prefs . value , defaults , props . thread ?. generator )
74
+ } )
75
+
76
+ function toggleShow ( ) {
77
+ prefs . value . show = ! prefs . value . show
78
+ savePrefs ( )
79
+ }
73
80
74
81
function savePrefs ( ) {
75
- prefs . show = show . value
76
- prefs . model = model . value
77
- prefs . count = count . value
78
- localStorage . setItem ( prefsKey , JSON . stringify ( prefs ) )
82
+ if ( props . thread ) props . thread . generator = prefs
83
+ emit ( 'save' , prefs )
79
84
}
80
85
81
86
if ( ! system . value && props . promptId ) {
@@ -95,7 +100,7 @@ export default {
95
100
if ( ! validPrompt . value ) return
96
101
savePrefs ( )
97
102
98
- const content = `Provide ${ count . value } great descriptive prompts to generate images of ${ subject . value } in Stable Diffusion SDXL and Mid Journey. Respond with only the prompts in a JSON array. Example ["prompt1","prompt2"]`
103
+ const content = `Provide ${ prefs . value . count } great descriptive prompts to generate images of ${ prefs . value . subject } in Stable Diffusion SDXL and Mid Journey. Respond with only the prompts in a JSON array. Example ["prompt1","prompt2"]`
99
104
100
105
const msgs = [
101
106
{ role :'system' , content :system . value } ,
@@ -104,7 +109,7 @@ export default {
104
109
105
110
const request = new OpenAiChatCompletion ( {
106
111
tag : "admin" ,
107
- model : model . value ,
112
+ model : prefs . value . model ,
108
113
messages : msgs ,
109
114
temperature : 0.7 ,
110
115
maxTokens : 2048 ,
@@ -116,7 +121,7 @@ export default {
116
121
let json = api . response ?. choices [ 0 ] ?. message ?. content ?. trim ( ) ?? ''
117
122
console . debug ( api . response )
118
123
if ( json ) {
119
- results . value = [ ]
124
+ prefs . value . results = [ ]
120
125
const docPrefix = '```json'
121
126
if ( json . startsWith ( docPrefix ) ) {
122
127
json = json . substring ( docPrefix . length , json . length - 3 )
@@ -125,18 +130,20 @@ export default {
125
130
console . log ( 'json' , json )
126
131
const obj = JSON . parse ( json )
127
132
if ( Array . isArray ( obj ) ) {
128
- results . value = obj
133
+ prefs . value . results = obj
129
134
}
130
135
} catch ( e ) {
131
136
console . warn ( 'could not parse json' , e , json )
132
137
}
133
138
}
134
- if ( ! results . value . length ) {
139
+ if ( ! prefs . value . results . length ) {
135
140
error . value = createErrorStatus ( 'Could not parse prompts' )
141
+ } else {
142
+ savePrefs ( )
136
143
}
137
144
}
138
145
}
139
146
140
- return { client, system, request, show , subject , count , models, model , error, results , validPrompt , send }
147
+ return { client, system, request, prefs , models, error, validPrompt , toggleShow , send }
141
148
}
142
149
}
0 commit comments