wip export

This commit is contained in:
Mary Hipp 2024-08-15 09:00:11 -04:00
parent d36c43a10f
commit a9014673a0
4 changed files with 131 additions and 3 deletions

View File

@ -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"}
)

View File

@ -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')}

View File

@ -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;

View File

@ -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;
};
};
};
};
} }