Skip to content
Snippets Groups Projects
Commit 75a2cda5 authored by chris's avatar chris
Browse files

anystyle updated

parent fa4a0389
No related branches found
No related tags found
1 merge request!466Chatgpt demo
Showing
with 347 additions and 0 deletions
......@@ -22,10 +22,74 @@ import {
EssayService,
MatchingService,
MultipleDropDownService,
AnyStyleService,
} from 'wax-prosemirror-services';
import { DefaultSchema } from 'wax-prosemirror-core';
import invisibles, { hardBreak } from '@guardian/prosemirror-invisibles';
const API_KEY = '';
async function AnyStyleTransformation(prompt) {
const response = await fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${API_KEY}`,
},
body: JSON.stringify({
model: 'gpt-3.5-turbo',
messages: [
{
role: 'user',
content: prompt,
},
],
temperature: 0,
// max_tokens: 400,
// n: 1,
// stop: null,
}),
});
try {
const data = await response.json();
console.log(data);
return data.choices[0].message.content;
} catch (e) {
console.error(e);
} finally {
}
return prompt;
}
// async function AnyStyleTransformation(prompt) {
// const response = await fetch('https://api.openai.com/v1/completions', {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// Authorization: `Bearer ${API_KEY}`,
// },
// body: JSON.stringify({
// model: 'text-davinci-003',
// prompt: prompt,
// max_tokens: 400,
// n: 1,
// stop: null,
// temperature: 0.5,
// }),
// });
// try {
// const data = await response.json();
// console.log(data);
// return data.choices[0].text.trim();
// } catch (e) {
// console.error(e);
// } finally {
// console.log('We do cleanup here');
// }
// return 'Nothing found';
// }
export default {
MenuService: [
......@@ -47,6 +111,7 @@ export default {
'Lists',
'Images',
'Tables',
'AnyStyle',
'QuestionsDropDown',
'FullScreen',
],
......@@ -60,6 +125,9 @@ export default {
toolGroups: ['MultipleDropDown'],
},
],
AnyStyleService: {
AnyStyleTransformation: AnyStyleTransformation,
},
SchemaService: DefaultSchema,
RulesService: [emDash, ellipsis],
......@@ -67,6 +135,7 @@ export default {
PmPlugins: [columnResizing(), tableEditing(), invisibles([hardBreak()])],
services: [
new AnyStyleService(),
new MatchingService(),
new FillTheGapQuestionService(),
new MultipleChoiceQuestionService(),
......
......@@ -39,6 +39,7 @@ export { default as MultipleDropDownService } from './src/MultipleDropDownServic
export { default as OENContainersService } from './src/OENContainersService/OENContainersService';
export { default as YjsService } from './src/YjsService/YjsService';
export { default as AnyStyleService } from './src/AnyStyleService/AnyStyleService';
/*
ToolGroups
*/
......
import { Service } from 'wax-prosemirror-core';
import AnyStyleTool from './AnyStyleTool';
import AnyStyleToolGroupService from './AnyStyleToolGroupService/AnyStyleToolGroupService';
import AnyStylePlaceHolderPlugin from './plugins/AnyStylePlaceHolderPlugin';
import './anyStyle.css';
class AnyStyleService extends Service {
name = 'AnyStyleService';
boot() {
this.app.PmPlugins.add(
'anyStylePlaceHolder',
AnyStylePlaceHolderPlugin('anyStylePlaceHolder'),
);
}
register() {
this.container.bind('AnyStyleTool').to(AnyStyleTool);
}
dependencies = [new AnyStyleToolGroupService()];
}
export default AnyStyleService;
import React, { useContext } from 'react';
import { v4 as uuidv4 } from 'uuid';
import { isEmpty } from 'lodash';
import { injectable } from 'inversify';
import { WaxContext, Commands, Tools } from 'wax-prosemirror-core';
import AnyStyleButton from './components/AnyStyleButton';
import replaceText from './replaceText';
@injectable()
class AnyStyleTool extends Tools {
title = 'ChatGPT';
name = 'ChatGPT';
label = 'ChatGPT';
get run() {
return true;
}
select = activeView => {
return true;
};
get enable() {
return state => {
return true;
};
}
renderTool(view) {
if (isEmpty(view)) return null;
const context = useContext(WaxContext);
const anyStyle = replaceText(
view,
this.config.get('config.AnyStyleService').AnyStyleTransformation,
this.pmplugins.get('anyStylePlaceHolder'),
context,
);
return this.isDisplayed() ? (
<AnyStyleButton
anyStyle={anyStyle}
item={this.toJSON()}
key={uuidv4()}
view={view}
/>
) : null;
}
// renderTool(view) {
// if (isEmpty(view)) return null;
// const context = useContext(WaxContext);
// const upload = fileUpload(
// view,
// this.config.get('fileUpload'),
// this.pmplugins.get('imagePlaceHolder'),
// context,
// );
// return this.isDisplayed() ? (
// <ImageUpload
// fileUpload={upload}
// item={this.toJSON()}
// key={uuidv4()}
// view={view}
// />
// ) : null;
// }
}
export default AnyStyleTool;
import { injectable, inject } from 'inversify';
import { ToolGroup } from 'wax-prosemirror-core';
@injectable()
class Anystyle extends ToolGroup {
tools = [];
constructor(@inject('AnyStyleTool') anyStyleTool) {
super();
this.tools = [anyStyleTool];
}
}
export default Anystyle;
import { Service } from 'wax-prosemirror-core';
import AnyStyle from './AnyStyle';
class AnyStyleToolGroupService extends Service {
register() {
this.container.bind('AnyStyle').to(AnyStyle);
}
}
export default AnyStyleToolGroupService;
placeholder-any-style:before {
position: relative;
top: 3px;
content: url("data:image/svg+xml; utf8, <svg xmlns='http://www.w3.org/2000/svg' height='24' width='24'><path d='M8 20h8v-3q0-1.65-1.175-2.825Q13.65 13 12 13q-1.65 0-2.825 1.175Q8 15.35 8 17Zm-4 2v-2h2v-3q0-1.525.713-2.863Q7.425 12.8 8.7 12q-1.275-.8-1.987-2.138Q6 8.525 6 7V4H4V2h16v2h-2v3q0 1.525-.712 2.862Q16.575 11.2 15.3 12q1.275.8 1.988 2.137Q18 15.475 18 17v3h2v2Z' /></svg>");
}
\ No newline at end of file
/* eslint react/prop-types: 0 */
import React, { useContext, useMemo, useEffect } from 'react';
import { WaxContext, DocumentHelpers, MenuButton } from 'wax-prosemirror-core';
import { TextSelection } from 'prosemirror-state';
const AnyStyleButton = ({ view = {}, item, anyStyle }) => {
const { active, icon, label, run, select, title } = item;
const {
app,
pmViews: { main },
activeViewId,
activeView,
} = useContext(WaxContext);
const { state } = view;
const handleMouseDown = (e, editorState) => {
e.preventDefault();
const {
selection: { $from, $to },
} = editorState;
/* this is the content that we have to get from the selection */
const textSelection = new TextSelection($from, $to);
const content = textSelection.content();
anyStyle(content.content.content[0].textContent);
};
useEffect(() => {}, []);
const isActive = !!active(state, activeViewId);
let isDisabled = !select(state, activeViewId, activeView);
const isEditable = main.props.editable(editable => {
return editable;
});
if (!isEditable) isDisabled = true;
const AnyStyleButtonComponent = useMemo(
() => (
<MenuButton
active={isActive || false}
disabled={isDisabled}
iconName={icon}
label={label}
onMouseDown={e => handleMouseDown(e, view.state, view.dispatch)}
title={title}
/>
),
[isActive, isDisabled],
);
return AnyStyleButtonComponent;
};
export default AnyStyleButton;
/* eslint-disable no-param-reassign */
import { Plugin, PluginKey } from 'prosemirror-state';
import { Decoration, DecorationSet } from 'prosemirror-view';
export default key =>
new Plugin({
key: new PluginKey(key),
state: {
init: function init() {
return DecorationSet.empty;
},
apply: function apply(tr, set) {
// Adjust decoration positions to changes made by the transaction
set = set.map(tr.mapping, tr.doc);
// See if the transaction adds or removes any placeholders
const action = tr.getMeta(this);
if (action && action.add) {
const widget = document.createElement('placeholder-any-style');
const deco = Decoration.widget(action.add.pos, widget, {
id: action.add.id,
});
set = set.add(tr.doc, [deco]);
} else if (action && action.remove) {
set = set.remove(
set.find(null, null, spec => spec.id === action.remove.id),
);
}
return set;
},
},
props: {
decorations: function decorations(state) {
return this.getState(state);
},
},
});
import { v4 as uuidv4 } from 'uuid';
import { DOMParser } from 'prosemirror-model';
const findPlaceholder = (state, id, placeholderPlugin) => {
const decos = placeholderPlugin.getState(state);
const found = decos.find(null, null, spec => spec.id === id);
return found.length ? found[0].from : null;
};
const elementFromString = string => {
const wrappedValue = `<body>${string}</body>`;
return new window.DOMParser().parseFromString(wrappedValue, 'text/html').body;
};
export default (
view,
AnyStyleTransformation,
placeholderPlugin,
context,
) => data => {
const { state } = view;
// A fresh object to act as the ID for this upload
const id = {};
// Replace the selection with a placeholder
const { tr } = state;
if (!tr.selection.empty) tr.deleteSelection();
tr.setMeta(placeholderPlugin, {
add: { id, pos: tr.selection.from },
});
view.dispatch(tr);
AnyStyleTransformation(data).then(
text => {
const pos = findPlaceholder(view.state, id, placeholderPlugin);
// If the content around the placeholder has been deleted, drop
// the image
if (pos == null) {
return;
}
const parser = DOMParser.fromSchema(
context.pmViews.main.state.config.schema,
);
const parsedContent = parser.parse(elementFromString(text));
// Otherwise, insert it at the placeholder's position, and remove
// the placeholder
context.pmViews[context.activeViewId].dispatch(
context.pmViews[context.activeViewId].state.tr
.replaceWith(pos, pos, parsedContent)
.setMeta(placeholderPlugin, { remove: { id } }),
);
},
() => {
// On failure, just clean up the placeholder
view.dispatch(tr.setMeta(placeholderPlugin, { remove: { id } }));
},
);
};
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment