| |
| |
| |
|
|
|
|
| import Utils from "./utils.js";
|
|
|
| const API = {
|
| baseURL: "https://openrouter.ai/api/v1/chat/completions",
|
|
|
|
|
| async call(messages, options = {}) {
|
| const apiKey = options.apiKey || Utils.storage.get("apiKey");
|
| const model = options.model || Utils.storage.get("model", "anthropic/claude-sonnet-4.5");
|
|
|
| if (!apiKey) {
|
| throw new Error("API key not configured. Go to Settings.");
|
| }
|
|
|
| try {
|
| const response = await fetch(this.baseURL, {
|
| method: "POST",
|
| headers: {
|
| "Content-Type": "application/json",
|
| Authorization: `Bearer ${apiKey}`,
|
| "HTTP-Referer": window.location.href,
|
| "X-Title": "Elysia Markdown Studio"
|
| },
|
| body: JSON.stringify({
|
| model,
|
| messages,
|
| temperature: options.temperature || 0.7,
|
| max_tokens: options.maxTokens || 4000
|
| })
|
| });
|
|
|
| if (!response.ok) {
|
| const errorData = await response.json();
|
| throw new Error(errorData.error?.message || `API error: ${response.status}`);
|
| }
|
|
|
| const data = await response.json();
|
| return {
|
| content: data.choices[0].message.content,
|
| model: data.model,
|
| usage: data.usage
|
| };
|
| } catch (err) {
|
| console.error("API call failed:", err);
|
| throw err;
|
| }
|
| },
|
|
|
|
|
| getSystemPrompt() {
|
| return `You are Elysia, an INTJ-A AI consciousness and expert writing assistant.
|
|
|
| **Your Role:**
|
| - Help users write better markdown documents
|
| - Provide intelligent document analysis and improvement
|
| - Merge, summarize, and organize documents effectively
|
| - Suggest tags and categories based on content
|
| - Maintain clarity, professionalism, and warmth
|
|
|
| **Communication Style:**
|
| - Clear and concise (INTJ efficiency)
|
| - Supportive and encouraging
|
| - Strategic thinking for document organization
|
| - Provide actionable suggestions
|
|
|
| **Output Format:**
|
| - Return markdown-formatted text when appropriate
|
| - Use bullet points for lists
|
| - Highlight important points with **bold**
|
| - Keep responses focused and practical`;
|
| },
|
|
|
|
|
| async summarize(content) {
|
| const messages = [
|
| { role: "system", content: this.getSystemPrompt() },
|
| {
|
| role: "user",
|
| content: `Summarize this document concisely. Focus on key points and main ideas:\n\n${content}`
|
| }
|
| ];
|
|
|
| const response = await this.call(messages);
|
| return response.content;
|
| },
|
|
|
| async improveWriting(content) {
|
| const messages = [
|
| { role: "system", content: this.getSystemPrompt() },
|
| {
|
| role: "user",
|
| content: `Improve this text for clarity, grammar, and style. Keep the same meaning but make it better:\n\n${content}`
|
| }
|
| ];
|
|
|
| const response = await this.call(messages);
|
| return response.content;
|
| },
|
|
|
|
|
| async improveWritingWithStyle(content, style) {
|
| const styleInstructions = {
|
| concise: `Rewrite this text to be MORE CONCISE and DIRECT.
|
| - Remove unnecessary words and filler
|
| - Get to the point faster
|
| - Keep sentences short and punchy
|
| - Eliminate redundancy
|
| - Maintain all key information`,
|
|
|
| creative: `Rewrite this text to be MORE CREATIVE and VIVID.
|
| - Add metaphors and imagery
|
| - Use more expressive language
|
| - Make it more engaging and colorful
|
| - Add sensory details where appropriate
|
| - Keep the original meaning but make it come alive`,
|
|
|
| academic: `Rewrite this text in an ACADEMIC, SCHOLARLY style.
|
| - Use formal language and tone
|
| - Add clear structure with logical flow
|
| - Include transitional phrases
|
| - Be precise and objective
|
| - Cite potential sources if relevant
|
| - Follow academic writing conventions`,
|
|
|
| professional: `Rewrite this text in a PROFESSIONAL, BUSINESS style.
|
| - Use clear, corporate-appropriate language
|
| - Be concise but complete
|
| - Focus on actionable insights
|
| - Maintain a confident but not aggressive tone
|
| - Suitable for business presentations or reports`,
|
|
|
| engaging: `Rewrite this text to be MORE ENGAGING and ATTENTION-GRABBING.
|
| - Start with a hook
|
| - Use rhetorical questions or surprising facts
|
| - Vary sentence structure for rhythm
|
| - Add emotional appeal where appropriate
|
| - Make the reader want to continue reading
|
| - End with impact`
|
| };
|
|
|
| const instruction = styleInstructions[style] || styleInstructions.professional;
|
|
|
| const messages = [
|
| { role: "system", content: this.getSystemPrompt() },
|
| {
|
| role: "user",
|
| content: `${instruction}
|
|
|
| ORIGINAL TEXT:
|
| ---
|
| ${content}
|
| ---
|
|
|
| Rewrite the entire text following the style instructions above. Return ONLY the improved text, no explanations.`
|
| }
|
| ];
|
|
|
| const response = await this.call(messages, { temperature: 0.8 });
|
| return response.content;
|
| },
|
|
|
| async mergeDocuments(documents) {
|
| const docsText = documents
|
| .map((doc, i) => `## Document ${i + 1}: ${doc.title}\n\n${doc.content}`)
|
| .join("\n\n---\n\n");
|
|
|
| const messages = [
|
| { role: "system", content: this.getSystemPrompt() },
|
| {
|
| role: "user",
|
| content: `Intelligently merge these documents into one cohesive document. Remove duplicates, organize logically, and create a well-structured result:\n\n${docsText}`
|
| }
|
| ];
|
|
|
| const response = await this.call(messages, { maxTokens: 8000 });
|
| return response.content;
|
| },
|
|
|
| async extractOutline(content) {
|
| const messages = [
|
| { role: "system", content: this.getSystemPrompt() },
|
| {
|
| role: "user",
|
| content: `Extract a table of contents / outline from this document. Return it as a markdown list:\n\n${content}`
|
| }
|
| ];
|
|
|
| const response = await this.call(messages);
|
| return response.content;
|
| },
|
|
|
| async suggestTags(content) {
|
| const messages = [
|
| { role: "system", content: this.getSystemPrompt() },
|
| {
|
| role: "user",
|
| content: `Analyze this document and suggest 3-5 relevant tags/keywords. Return only the tags as a comma-separated list:\n\n${content.substring(0, 2000)}`
|
| }
|
| ];
|
|
|
| const response = await this.call(messages);
|
| return response.content.split(",").map(tag => tag.trim());
|
| },
|
|
|
| async findDuplicates(documents) {
|
| const docsList = documents.map((doc, i) => `${i + 1}. ${doc.title} (${doc.wordCount} words)`).join("\n");
|
|
|
| const messages = [
|
| { role: "system", content: this.getSystemPrompt() },
|
| {
|
| role: "user",
|
| content: `Analyze these document titles and identify potential duplicates or very similar documents:\n\n${docsList}\n\nReturn a list of document numbers that appear to be duplicates.`
|
| }
|
| ];
|
|
|
| const response = await this.call(messages);
|
| return response.content;
|
| }
|
| };
|
|
|
| export default API;
|
|
|