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

View File

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

View File

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

View File

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