+
@@ -19,13 +20,15 @@
import { defineComponent } from 'vue';
import { ElDrawer, ElButton } from 'element-plus';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
+import ImageNavigator from '@/components/common/ImageNavigator.vue';
export default defineComponent({
name: 'LayoutMidjourney',
components: {
ElDrawer,
ElButton,
- FontAwesomeIcon
+ FontAwesomeIcon,
+ ImageNavigator
},
data() {
return {
diff --git a/src/models/flux.ts b/src/models/flux.ts
new file mode 100644
index 00000000..53356b96
--- /dev/null
+++ b/src/models/flux.ts
@@ -0,0 +1,45 @@
+export interface IFluxConfig {
+ action?: string;
+ prompt?: string;
+ model?: string;
+ callback_url?: string;
+}
+
+export interface IFluxGenerateRequest {
+ action?: string;
+ prompt?: string;
+ model?: string;
+ callback_url?: string;
+ mirror?: boolean;
+}
+export interface IFluxImage {
+ image_url?: string;
+ timings?: number;
+ prompt?: string;
+ action?: string;
+ seed?: number;
+}
+export interface IFluxGenerateResponse {
+ success: boolean;
+ task_id: string;
+ trace_id: string;
+ data?: IFluxImage[];
+ error?: {
+ code?: string;
+ message?: string;
+ };
+}
+
+export interface IFluxTask {
+ id: string;
+ created_at?: number;
+ request?: IFluxGenerateRequest;
+ response?: IFluxGenerateResponse;
+}
+
+export type IFluxTaskResponse = IFluxTask;
+
+export interface IFluxTasksResponse {
+ count: number;
+ items: IFluxTask[];
+}
diff --git a/src/models/index.ts b/src/models/index.ts
index c5ba4a80..159b3147 100644
--- a/src/models/index.ts
+++ b/src/models/index.ts
@@ -14,6 +14,7 @@ export * from './credential';
export * from './qrart';
export * from './luma';
export * from './pika';
+export * from './flux';
export * from './hailuo';
export * from './headshots';
export * from './suno';
diff --git a/src/operators/flux.ts b/src/operators/flux.ts
new file mode 100644
index 00000000..ac936e50
--- /dev/null
+++ b/src/operators/flux.ts
@@ -0,0 +1,112 @@
+import axios, { AxiosResponse } from 'axios';
+import { IFluxGenerateRequest, IFluxGenerateResponse, IFluxTaskResponse, IFluxTasksResponse } from '@/models';
+import { BASE_URL_API } from '@/constants';
+
+class FluxOperator {
+ async task(id: string, options: { token: string }): Promise
> {
+ return await axios.post(
+ `/flux/tasks`,
+ {
+ action: 'retrieve',
+ id: id
+ },
+ {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json',
+ authorization: `Bearer ${options.token}`,
+ 'x-record-exempt': 'true'
+ },
+ baseURL: BASE_URL_API
+ }
+ );
+ }
+
+ async tasks(
+ filter: {
+ ids?: string[];
+ applicationId?: string;
+ userId?: string;
+ type?: string;
+ limit?: number;
+ offset?: number;
+ createdAtMax?: number;
+ createdAtMin?: number;
+ },
+ options: { token: string }
+ ): Promise> {
+ return await axios.post(
+ `/flux/tasks`,
+ {
+ action: 'retrieve_batch',
+ ...(filter.ids
+ ? {
+ ids: filter.ids
+ }
+ : {}),
+ ...(filter.applicationId
+ ? {
+ application_id: filter.applicationId
+ }
+ : {}),
+ ...(filter.userId
+ ? {
+ user_id: filter.userId
+ }
+ : {}),
+ ...(filter.type
+ ? {
+ type: filter.type
+ }
+ : {}),
+ ...(filter.limit !== undefined
+ ? {
+ limit: filter.limit
+ }
+ : {}),
+ ...(filter.offset !== undefined
+ ? {
+ offset: filter.offset
+ }
+ : {}),
+ ...(filter.createdAtMax !== undefined
+ ? {
+ created_at_max: filter.createdAtMax
+ }
+ : {}),
+ ...(filter.createdAtMin !== undefined
+ ? {
+ created_at_min: filter.createdAtMin
+ }
+ : {})
+ },
+ {
+ headers: {
+ accept: 'application/json',
+ 'content-type': 'application/json',
+ authorization: `Bearer ${options.token}`,
+ 'x-record-exempt': 'true'
+ },
+ baseURL: BASE_URL_API
+ }
+ );
+ }
+
+ async generate(
+ data: IFluxGenerateRequest,
+ options: {
+ token: string;
+ }
+ ): Promise> {
+ return await axios.post('/flux/images', data, {
+ headers: {
+ authorization: `Bearer ${options.token}`,
+ 'content-type': 'application/json',
+ accept: 'application/x-ndjson'
+ },
+ baseURL: BASE_URL_API
+ });
+ }
+}
+
+export const fluxOperator = new FluxOperator();
diff --git a/src/operators/index.ts b/src/operators/index.ts
index 42678666..c2326067 100644
--- a/src/operators/index.ts
+++ b/src/operators/index.ts
@@ -14,6 +14,7 @@ export * from './credential';
export * from './qrart';
export * from './luma';
export * from './pika';
+export * from './flux';
export * from './hailuo';
export * from './headshots';
export * from './site';
diff --git a/src/pages/flux/Index.vue b/src/pages/flux/Index.vue
new file mode 100644
index 00000000..bbb02e82
--- /dev/null
+++ b/src/pages/flux/Index.vue
@@ -0,0 +1,229 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pages/site/Index.vue b/src/pages/site/Index.vue
index eb7872ff..36e80272 100644
--- a/src/pages/site/Index.vue
+++ b/src/pages/site/Index.vue
@@ -181,6 +181,7 @@
'suno',
'luma',
'pika',
+ 'flux',
'hailuo',
'headshots',
'support'
diff --git a/src/router/constants.ts b/src/router/constants.ts
index 1efc1b09..098d2176 100644
--- a/src/router/constants.ts
+++ b/src/router/constants.ts
@@ -19,6 +19,9 @@ export const ROUTE_LUMA_HISTORY = 'luma-history';
export const ROUTE_PIKA_INDEX = 'pika-index';
export const ROUTE_PIKA_HISTORY = 'pika-history';
+export const ROUTE_FLUX_INDEX = 'flux-index';
+export const ROUTE_FLUX_HISTORY = 'flux-history';
+
export const ROUTE_HAILUO_INDEX = 'hailuo-index';
export const ROUTE_HAILUO_HISTORY = 'hailuo-history';
diff --git a/src/router/flux.ts b/src/router/flux.ts
new file mode 100644
index 00000000..c1a545b5
--- /dev/null
+++ b/src/router/flux.ts
@@ -0,0 +1,16 @@
+import { ROUTE_FLUX_INDEX } from './constants';
+
+export default {
+ path: '/flux',
+ meta: {
+ auth: true
+ },
+ component: () => import('@/layouts/Main.vue'),
+ children: [
+ {
+ path: '',
+ name: ROUTE_FLUX_INDEX,
+ component: () => import('@/pages/flux/Index.vue')
+ }
+ ]
+};
diff --git a/src/router/index.ts b/src/router/index.ts
index 6f4252fb..ee7b483a 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -8,6 +8,7 @@ import chatdoc from './chatdoc';
import qrart from './qrart';
import luma from './luma';
import pika from './pika';
+import flux from './flux';
import hailuo from './hailuo';
import headshots from './headshots';
import suno from './suno';
@@ -37,6 +38,7 @@ const routes = [
qrart,
luma,
pika,
+ flux,
hailuo,
headshots,
suno,
diff --git a/src/store/common/models.ts b/src/store/common/models.ts
index f806b6e8..c71fd948 100644
--- a/src/store/common/models.ts
+++ b/src/store/common/models.ts
@@ -5,6 +5,7 @@ import { IChatdocState } from '../chatdoc/models';
import { IQrartState } from '../qrart/models';
import { ILumaState } from '../luma/models';
import { IPikaState } from '../pika/models';
+import { IFluxState } from '../flux/models';
import { IHailuoState } from '../hailuo/models';
import { IHeadshotsState } from '../headshots/models';
import { ISunoState } from '../suno/models';
@@ -36,6 +37,7 @@ export interface IRootState extends ICommonState {
qrart: IQrartState;
luma: ILumaState;
pika: IPikaState;
+ flux: IFluxState;
hailuo: IHailuoState;
headshots: IHeadshotsState;
suno: ISunoState;
diff --git a/src/store/flux/actions.ts b/src/store/flux/actions.ts
new file mode 100644
index 00000000..a31d850d
--- /dev/null
+++ b/src/store/flux/actions.ts
@@ -0,0 +1,175 @@
+import { applicationOperator, fluxOperator, serviceOperator } from '@/operators';
+import { IFluxState } from './models';
+import { ActionContext } from 'vuex';
+import { IRootState } from '../common/models';
+import { IApplication, ICredential, IFluxConfig, IFluxTask, IService, IApplicationType } from '@/models';
+import { Status } from '@/models/common';
+import { FLUX_SERVICE_ID } from '@/constants';
+import { mergeAndSortLists } from '@/utils/merge';
+
+export const resetAll = ({ commit }: ActionContext): void => {
+ commit('resetAll');
+};
+
+export const setCredential = async ({ commit }: any, payload: ICredential): Promise => {
+ console.debug('set credential', payload);
+ commit('setCredential', payload);
+};
+
+export const setConfig = ({ commit }: any, payload: IFluxConfig) => {
+ commit('setConfig', payload);
+};
+
+export const setService = async ({ commit }: any, payload: IService): Promise => {
+ console.debug('set service', payload);
+ commit('setService', payload);
+};
+
+export const setApplication = ({ commit }: any, payload: IApplication[]) => {
+ commit('setApplication', payload);
+};
+
+export const getApplications = async ({
+ commit,
+ state,
+ rootState
+}: ActionContext): Promise => {
+ console.debug('start to get applications for flux');
+ return new Promise((resolve, reject) => {
+ state.status.getApplications = Status.Request;
+ applicationOperator
+ .getAll({
+ user_id: rootState?.user?.id,
+ service_id: FLUX_SERVICE_ID
+ })
+ .then((response) => {
+ console.debug('get applications success', response?.data);
+ state.status.getApplications = Status.Success;
+ // check if there is any application with 'Period' type
+ const application = response.data.items?.find((application) => application?.type === IApplicationType.PERIOD);
+ const application2 = response.data.items?.find((application) => application?.type === IApplicationType.USAGE);
+ if (application && application?.remaining_amount) {
+ console.debug('set application with Period', application);
+ commit('setApplication', application);
+ const credential = application?.credentials?.find(
+ (credential) => credential?.host === window.location.origin
+ );
+ console.debug('set credential with Period', application);
+ commit('setCredential', credential);
+ } else if (application2) {
+ console.debug('set application with Usage', application2);
+ commit('setApplication', application2);
+ const credential = application2?.credentials?.find(
+ (credential) => credential?.host === window.location.origin
+ );
+ console.debug('set credential with Usage', application);
+ commit('setCredential', credential);
+ } else {
+ console.debug('set application with null', response.data.items?.[0]);
+ commit('setApplication', response.data.items?.[0]);
+ }
+ resolve(response.data.items);
+ console.debug('save application success', response.data.items[0]);
+ })
+ .catch((error) => {
+ state.status.getApplications = Status.Error;
+ reject(error);
+ });
+ });
+};
+
+export const setTasks = ({ commit }: any, payload: any) => {
+ commit('setTasks', payload);
+};
+
+export const setTasksItems = ({ commit }: any, payload: IFluxTask[]) => {
+ commit('setTasksItems', payload);
+};
+
+export const setTasksTotal = ({ commit }: any, payload: number) => {
+ commit('setTasksTotal', payload);
+};
+
+export const setTasksActive = ({ commit }: any, payload: IFluxTask) => {
+ commit('setTasksActive', payload);
+};
+
+export const getService = async ({ commit, state }: ActionContext): Promise => {
+ return new Promise((resolve, reject) => {
+ console.debug('start to get service for flux');
+ state.status.getService = Status.Request;
+ serviceOperator
+ .get(FLUX_SERVICE_ID)
+ .then((response) => {
+ state.status.getService = Status.Success;
+ commit('setService', response.data);
+ resolve(response.data);
+ })
+ .catch((error) => {
+ state.status.getService = Status.Error;
+ reject(error);
+ });
+ });
+};
+
+export const getTasks = async (
+ { commit, state, rootState }: ActionContext,
+ {
+ offset,
+ limit,
+ createdAtMin,
+ createdAtMax
+ }: { offset?: number; limit?: number; createdAtMin?: number; createdAtMax?: number }
+): Promise => {
+ return new Promise((resolve, reject) => {
+ console.debug('start to get tasks', offset, limit);
+ const credential = state.credential;
+ const token = credential?.token;
+ if (!token) {
+ return reject('no token');
+ }
+ fluxOperator
+ .tasks(
+ {
+ userId: rootState?.user?.id,
+ createdAtMin,
+ createdAtMax,
+ type: 'images'
+ },
+ {
+ token
+ }
+ )
+ .then((response) => {
+ console.debug('get videos tasks success', response.data.items);
+ // merge with existing tasks
+ const existingItems = state?.tasks?.items || [];
+ console.debug('existing items', existingItems);
+ const newItems = response.data.items || [];
+ console.debug('new items', newItems);
+ // sort and de-duplicate using created_at
+ const mergedItems = mergeAndSortLists(existingItems, newItems);
+ commit('setTasksItems', mergedItems);
+ commit('setTasksTotal', response.data.count);
+ resolve(response.data.items);
+ })
+ .catch((error) => {
+ return reject(error);
+ });
+ });
+};
+
+export default {
+ setService,
+ getService,
+ resetAll,
+ setCredential,
+ setConfig,
+ setApplication,
+ getApplications,
+ setTasks,
+ setTasksItems,
+ setTasksTotal,
+ setTasksActive,
+ getTasks
+};
diff --git a/src/store/flux/index.ts b/src/store/flux/index.ts
new file mode 100644
index 00000000..c37bd113
--- /dev/null
+++ b/src/store/flux/index.ts
@@ -0,0 +1,14 @@
+import { Module } from 'vuex';
+import { IFluxState } from './models';
+import actions from './actions';
+import mutations from './mutations';
+import state from './state';
+
+export const flux: Module = {
+ namespaced: true,
+ state,
+ mutations,
+ actions
+};
+
+export default flux;
diff --git a/src/store/flux/models.ts b/src/store/flux/models.ts
new file mode 100644
index 00000000..5d0b5b0b
--- /dev/null
+++ b/src/store/flux/models.ts
@@ -0,0 +1,22 @@
+import { IApplication, ICredential, IService, Status } from '@/models';
+import { IFluxConfig, IFluxTask } from '@/models';
+
+export interface IFluxState {
+ application: IApplication | undefined;
+ applications: IApplication[] | undefined;
+ service: IService | undefined;
+ credential: ICredential | undefined;
+ config: IFluxConfig | undefined;
+ tasks:
+ | {
+ items: IFluxTask[] | undefined;
+ total: number | undefined;
+ active: IFluxTask | undefined;
+ }
+ | undefined;
+ status: {
+ getService: Status;
+ getApplications: Status;
+ getTasks: Status;
+ };
+}
diff --git a/src/store/flux/mutations.ts b/src/store/flux/mutations.ts
new file mode 100644
index 00000000..e5e951c3
--- /dev/null
+++ b/src/store/flux/mutations.ts
@@ -0,0 +1,71 @@
+import { IApplication, ICredential, IFluxConfig, IFluxTask, IService } from '@/models';
+import { IFluxState } from './models';
+
+export const resetAll = (state: IFluxState): void => {
+ state.service = undefined;
+ state.application = undefined;
+ state.config = undefined;
+ state.credential = undefined;
+ state.tasks = undefined;
+};
+
+export const setService = (state: IFluxState, payload: IService): void => {
+ state.service = payload;
+};
+
+export const setCredential = (state: IFluxState, payload: ICredential): void => {
+ state.credential = payload;
+};
+
+export const setApplication = (state: IFluxState, payload: IApplication): void => {
+ state.application = payload;
+};
+
+export const setApplications = (state: IFluxState, payload: IApplication[]): void => {
+ state.applications = payload;
+};
+
+export const setConfig = (state: IFluxState, payload: IFluxConfig): void => {
+ state.config = payload;
+};
+
+export const setTasksItems = (state: IFluxState, payload: IFluxTask[]): void => {
+ const newPayload = {
+ ...state.tasks,
+ items: payload
+ } as typeof state.tasks;
+ state.tasks = newPayload;
+};
+
+export const setTasksTotal = (state: IFluxState, payload: number): void => {
+ const newPayload = {
+ ...state.tasks,
+ total: payload
+ } as typeof state.tasks;
+ state.tasks = newPayload;
+};
+
+export const setTasksActive = (state: IFluxState, payload: IFluxTask): void => {
+ const newPayload = {
+ ...state.tasks,
+ active: payload
+ } as typeof state.tasks;
+ state.tasks = newPayload;
+};
+
+export const setTasks = (state: IFluxState, payload: any): void => {
+ state.tasks = payload;
+};
+
+export default {
+ setTasks,
+ setApplication,
+ setApplications,
+ setConfig,
+ setCredential,
+ setService,
+ setTasksActive,
+ setTasksItems,
+ setTasksTotal,
+ resetAll
+};
diff --git a/src/store/flux/persist.ts b/src/store/flux/persist.ts
new file mode 100644
index 00000000..fd946a43
--- /dev/null
+++ b/src/store/flux/persist.ts
@@ -0,0 +1 @@
+export default ['flux.credential', 'flux.application'];
diff --git a/src/store/flux/state.ts b/src/store/flux/state.ts
new file mode 100644
index 00000000..7c0c6e5f
--- /dev/null
+++ b/src/store/flux/state.ts
@@ -0,0 +1,18 @@
+import { IFluxState } from './models';
+import { Status } from '@/models';
+
+export default (): IFluxState => {
+ return {
+ service: undefined,
+ application: undefined,
+ applications: undefined,
+ tasks: undefined,
+ credential: undefined,
+ config: undefined,
+ status: {
+ getService: Status.None,
+ getApplications: Status.None,
+ getTasks: Status.None
+ }
+ };
+};
diff --git a/src/store/index.ts b/src/store/index.ts
index 745a0197..234bf437 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -6,6 +6,7 @@ import chatdoc from './chatdoc';
import qrart from './qrart';
import luma from './luma';
import pika from './pika';
+import flux from './flux';
import hailuo from './hailuo';
import headshots from './headshots';
import suno from './suno';
@@ -16,6 +17,7 @@ import persistChatdoc from './chatdoc/persist';
import persistQrart from './qrart/persist';
import persistLuma from './luma/persist';
import persistPika from './pika/persist';
+import persistFlux from './flux/persist';
import persistHailuo from './hailuo/persist';
import persistHeadshots from './headshots/persist';
import persistSuno from './suno/persist';
@@ -29,6 +31,7 @@ const store = createStore({
qrart: qrart,
luma: luma,
pika: pika,
+ flux: flux,
hailuo: hailuo,
headshots: headshots,
suno: suno,
@@ -44,6 +47,7 @@ const store = createStore({
...persistQrart,
...persistLuma,
...persistPika,
+ ...persistFlux,
...persistHailuo,
...persistHeadshots,
...persistSuno