mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
wip export
This commit is contained in:
parent
d36c43a10f
commit
a9014673a0
@ -1,10 +1,11 @@
|
|||||||
|
import csv
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import pydantic
|
import pydantic
|
||||||
from fastapi import APIRouter, File, Form, HTTPException, Path, UploadFile
|
from fastapi import APIRouter, File, Form, HTTPException, Path, Response, UploadFile
|
||||||
from fastapi.responses import FileResponse
|
from fastapi.responses import FileResponse
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
@ -225,3 +226,30 @@ async def get_style_preset_image(
|
|||||||
return response
|
return response
|
||||||
except Exception:
|
except Exception:
|
||||||
raise HTTPException(status_code=404)
|
raise HTTPException(status_code=404)
|
||||||
|
|
||||||
|
|
||||||
|
@style_presets_router.get(
|
||||||
|
"/export",
|
||||||
|
operation_id="export_style_presets",
|
||||||
|
responses={200: {"content": {"text/csv": {}}, "description": "A CSV file with the requested data."}},
|
||||||
|
status_code=200,
|
||||||
|
)
|
||||||
|
async def export_style_presets():
|
||||||
|
# Create an in-memory stream to store the CSV data
|
||||||
|
output = io.StringIO()
|
||||||
|
writer = csv.writer(output)
|
||||||
|
|
||||||
|
# Write the header
|
||||||
|
writer.writerow(["name", "prompt", "negative_prompt"])
|
||||||
|
|
||||||
|
style_presets = ApiDependencies.invoker.services.style_preset_records.get_many()
|
||||||
|
|
||||||
|
for preset in style_presets:
|
||||||
|
writer.writerow([preset.name, preset.preset_data.positive_prompt, preset.preset_data.negative_prompt])
|
||||||
|
|
||||||
|
csv_data = output.getvalue()
|
||||||
|
output.close()
|
||||||
|
|
||||||
|
return Response(
|
||||||
|
content=csv_data, media_type="text/csv", headers={"Content-Disposition": "attachment; filename=data.csv"}
|
||||||
|
)
|
||||||
|
@ -4,12 +4,23 @@ import { useAppSelector } from 'app/store/storeHooks';
|
|||||||
import { $stylePresetModalState } from 'features/stylePresets/store/stylePresetModal';
|
import { $stylePresetModalState } from 'features/stylePresets/store/stylePresetModal';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PiPlusBold } from 'react-icons/pi';
|
import { PiDownloadBold, PiPlusBold } from 'react-icons/pi';
|
||||||
import type { StylePresetRecordWithImage } from 'services/api/endpoints/stylePresets';
|
import type { StylePresetRecordWithImage } from 'services/api/endpoints/stylePresets';
|
||||||
import { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
|
import { useLazyExportStylePresetsQuery, useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
|
||||||
|
|
||||||
import { StylePresetList } from './StylePresetList';
|
import { StylePresetList } from './StylePresetList';
|
||||||
import StylePresetSearch from './StylePresetSearch';
|
import StylePresetSearch from './StylePresetSearch';
|
||||||
|
import { toast } from '../../toast/toast';
|
||||||
|
|
||||||
|
const generateCSV = (data: any[]) => {
|
||||||
|
const header = ['Column1', 'Column2', 'Column3'];
|
||||||
|
const csvRows = [
|
||||||
|
header.join(','), // add header row
|
||||||
|
...data.map((row) => row.join(',')), // add data rows
|
||||||
|
];
|
||||||
|
|
||||||
|
return csvRows.join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
export const StylePresetMenu = () => {
|
export const StylePresetMenu = () => {
|
||||||
const searchTerm = useAppSelector((s) => s.stylePreset.searchTerm);
|
const searchTerm = useAppSelector((s) => s.stylePreset.searchTerm);
|
||||||
@ -47,6 +58,7 @@ export const StylePresetMenu = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const [exportStylePresets, { isLoading }] = useLazyExportStylePresetsQuery();
|
||||||
|
|
||||||
const handleClickAddNew = useCallback(() => {
|
const handleClickAddNew = useCallback(() => {
|
||||||
$stylePresetModalState.set({
|
$stylePresetModalState.set({
|
||||||
@ -56,10 +68,49 @@ export const StylePresetMenu = () => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleClickDownloadCsv = useCallback(async () => {
|
||||||
|
let blob;
|
||||||
|
try {
|
||||||
|
const response = await exportStylePresets().unwrap();
|
||||||
|
blob = new Blob([response], { type: 'text/csv' });
|
||||||
|
} catch (error) {
|
||||||
|
toast({
|
||||||
|
status: 'error',
|
||||||
|
title: 'Unable to generate and download export',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blob) {
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'data.csv';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
window.URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
toast({
|
||||||
|
status: 'success',
|
||||||
|
title: 'Export downloaded',
|
||||||
|
});
|
||||||
|
}, [exportStylePresets]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex flexDir="column" gap={2} padding={3} layerStyle="second" borderRadius="base">
|
<Flex flexDir="column" gap={2} padding={3} layerStyle="second" borderRadius="base">
|
||||||
<Flex alignItems="center" gap={2} w="full" justifyContent="space-between">
|
<Flex alignItems="center" gap={2} w="full" justifyContent="space-between">
|
||||||
<StylePresetSearch />
|
<StylePresetSearch />
|
||||||
|
<IconButton
|
||||||
|
icon={<PiDownloadBold />}
|
||||||
|
tooltip={t('stylePresets.createPromptTemplate')}
|
||||||
|
aria-label={t('stylePresets.createPromptTemplate')}
|
||||||
|
onClick={handleClickDownloadCsv}
|
||||||
|
size="md"
|
||||||
|
variant="link"
|
||||||
|
w={8}
|
||||||
|
h={8}
|
||||||
|
isDisabled={isLoading}
|
||||||
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={<PiPlusBold />}
|
icon={<PiPlusBold />}
|
||||||
tooltip={t('stylePresets.createPromptTemplate')}
|
tooltip={t('stylePresets.createPromptTemplate')}
|
||||||
|
@ -92,6 +92,16 @@ export const stylePresetsApi = api.injectEndpoints({
|
|||||||
}),
|
}),
|
||||||
providesTags: ['FetchOnReconnect', { type: 'StylePreset', id: LIST_TAG }],
|
providesTags: ['FetchOnReconnect', { type: 'StylePreset', id: LIST_TAG }],
|
||||||
}),
|
}),
|
||||||
|
exportStylePresets: build.query<
|
||||||
|
string,
|
||||||
|
void
|
||||||
|
>({
|
||||||
|
query: () => ({
|
||||||
|
url: buildStylePresetsUrl("/export"),
|
||||||
|
responseHandler: response => response.text()
|
||||||
|
}),
|
||||||
|
providesTags: ['FetchOnReconnect', { type: 'StylePreset', id: LIST_TAG }],
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -100,4 +110,5 @@ export const {
|
|||||||
useDeleteStylePresetMutation,
|
useDeleteStylePresetMutation,
|
||||||
useUpdateStylePresetMutation,
|
useUpdateStylePresetMutation,
|
||||||
useListStylePresetsQuery,
|
useListStylePresetsQuery,
|
||||||
|
useLazyExportStylePresetsQuery
|
||||||
} = stylePresetsApi;
|
} = stylePresetsApi;
|
||||||
|
@ -1344,6 +1344,23 @@ export type paths = {
|
|||||||
patch?: never;
|
patch?: never;
|
||||||
trace?: never;
|
trace?: never;
|
||||||
};
|
};
|
||||||
|
"/api/v1/style_presets/export": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Export Style Presets */
|
||||||
|
get: operations["export_style_presets"];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
export type webhooks = Record<string, never>;
|
export type webhooks = Record<string, never>;
|
||||||
export type components = {
|
export type components = {
|
||||||
@ -18083,4 +18100,25 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
export_style_presets: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description A CSV file with the requested data. */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": unknown;
|
||||||
|
"text/csv": unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user