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 json
|
||||
import traceback
|
||||
from typing import Optional
|
||||
|
||||
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 PIL import Image
|
||||
from pydantic import BaseModel, Field
|
||||
@ -225,3 +226,30 @@ async def get_style_preset_image(
|
||||
return response
|
||||
except Exception:
|
||||
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 { useCallback } from 'react';
|
||||
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 { useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
|
||||
import { useLazyExportStylePresetsQuery, useListStylePresetsQuery } from 'services/api/endpoints/stylePresets';
|
||||
|
||||
import { StylePresetList } from './StylePresetList';
|
||||
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 = () => {
|
||||
const searchTerm = useAppSelector((s) => s.stylePreset.searchTerm);
|
||||
@ -47,6 +58,7 @@ export const StylePresetMenu = () => {
|
||||
});
|
||||
|
||||
const { t } = useTranslation();
|
||||
const [exportStylePresets, { isLoading }] = useLazyExportStylePresetsQuery();
|
||||
|
||||
const handleClickAddNew = useCallback(() => {
|
||||
$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 (
|
||||
<Flex flexDir="column" gap={2} padding={3} layerStyle="second" borderRadius="base">
|
||||
<Flex alignItems="center" gap={2} w="full" justifyContent="space-between">
|
||||
<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
|
||||
icon={<PiPlusBold />}
|
||||
tooltip={t('stylePresets.createPromptTemplate')}
|
||||
|
@ -92,6 +92,16 @@ export const stylePresetsApi = api.injectEndpoints({
|
||||
}),
|
||||
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,
|
||||
useUpdateStylePresetMutation,
|
||||
useListStylePresetsQuery,
|
||||
useLazyExportStylePresetsQuery
|
||||
} = stylePresetsApi;
|
||||
|
@ -1344,6 +1344,23 @@ export type paths = {
|
||||
patch?: 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 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…
Reference in New Issue
Block a user