File size: 15,484 Bytes
81f9934
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
import os
import time
import asyncio
import aiohttp
import json
from dotenv import load_dotenv

# Load environment variables
load_dotenv(encoding='utf-8')

# Check if running on Hugging Face Spaces
IS_HF_SPACE = os.environ.get("SPACE_ID") is not None

async def get_available_models():
    """Get a list of available models from OpenRouter"""
    if IS_HF_SPACE:
        api_key = os.environ.get("OPENROUTER_API_KEY")
    else:
        api_key = os.getenv("OPENROUTER_API_KEY")
        
    if not api_key:
        raise Exception("OPENROUTER_API_KEY not found in environment variables")
        
    url = "https://openrouter.ai/api/v1/models"
    
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }
    
    async with aiohttp.ClientSession() as session:
        async with session.get(url, headers=headers) as response:
            if response.status != 200:
                error_text = await response.text()
                raise Exception(f"OpenRouter API error: {response.status}, {error_text}")
            
            data = await response.json()
            return data["data"]


# Defining the PromptEnhancer class
class PromptEnhancer:
    def __init__(self, model="anthropic/claude-3-haiku", tools_dict={}):
        self.model = model
        self.prompt_tokens = 0
        self.completion_tokens = 0
        self.tools_dict = tools_dict
        
        # Get API key based on environment
        if IS_HF_SPACE:
            self.api_key = os.environ.get("OPENROUTER_API_KEY")
        else:
            self.api_key = os.getenv("OPENROUTER_API_KEY")
            
        self.base_url = "https://openrouter.ai/api/v1"
        
        if not self.api_key:
            print("Error: API Key is not loaded!")
        else:
            print(f"API Key Loaded: {self.api_key[:5]}********")

    async def call_llm(self, prompt):
        """Call the LLM with the given prompt using OpenRouter"""
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
            "HTTP-Referer": "https://huggingface.co" if IS_HF_SPACE else "http://localhost:3000"
        }
        
        data = {
            "model": self.model,
            "messages": [
                {"role": "system", 
                 "content": 
                     "You are a highly intelligent AI assistant. Your task is to analyze, and comprehend the provided prompt,\

                        then provide clear, and concise response based strictly on the given instructions.\

                        Do not include any additional explanations or context beyond the required output."
                 },
                {"role": "user", 
                 "content": prompt
                 } 
            ],
            "temperature": 0.0,  # from 0 (precise) to 2 (creative)
        }
        
        async with aiohttp.ClientSession() as session:
            async with session.post(f"{self.base_url}/chat/completions", headers=headers, json=data) as response:
                if response.status != 200:
                    error_text = await response.text()
                    raise Exception(f"OpenRouter API error: {response.status}, {error_text}")
                
                response_data = await response.json()
                
                # Update token counts if available in the response
                if "usage" in response_data:
                    self.prompt_tokens += response_data["usage"].get("prompt_tokens", 0)
                    self.completion_tokens += response_data["usage"].get("completion_tokens", 0)
                
                return response_data["choices"][0]["message"]["content"]


    async def analyze_and_expand_input(self, input_prompt):
        analysis_and_expansion_prompt = f"""

        You are a highly intelligent assistant. 

        Analyze the provided {{prompt}} and generate concise answers for the following key aspects:



        - **Main goal of the prompt:** Identify the core subject or request within the provided prompt.

        - **Persona:** Recommend the most relevant persona for the AI model to adopt (e.g., expert, teacher, conversational, etc.)

        - **Optimal output length:** Suggest an optimal output length (short, brief, medium, long) based on the task, and give an approximate number of words if it is suitable for the case.

        - **Most convenient output format:** Recommend the optimal format for the result (e.g., list, paragraph, code snippet, table, JSON, etc.).

        - **Specific requirements:** Highlight any special conditions, rules, or expectations stated or implied within the prompt.

        - **Suggested improvements:** Offer recommendations on how to modify or enhance the prompt for more precise or efficient output generation.

        - **One-shot prompting:** Create one related examples to guide the output generation.

        

        Then use them to reformulate and expand the provided {{prompt}}.

        Return the expanded prompt as output in text format. Refrain from explaining the generation process.



        Example 1:

        {{prompt}}: "Explain quantum entanglement to a 10-year-old."

        

        *thought_process*:

        - **Main goal of the prompt:** Simplify complex quantum physics concept for children.

        - **Persona:** Patient, friendly teacher

        - **Optimal output length:** Brief (100-150 words)

        - **Most convenient output format:** Narrative with analogy

        - **Specific requirements:** Age-appropriate explanation (10-year-old).

        - **Suggested improvements:** 

            - Request specific analogies

            - Include interactive elements

            - Add follow-up questions

            - Suggest visual aids

        - **One-shot prompting:**

        Output example:

            "Imagine you have two special pairs of socks. When you put one sock in your room and the other sock in the kitchen, 

            something magical happens! Whatever happens to one sock instantly affects the other sock. 

            If you turn one sock inside out, the other sock automatically turns inside out too, no matter how far apart they are!" 

        

        *output*:

        As a friendly science teacher, please explain quantum entanglement to a 10-year-old student using these guidelines:



        Start with a relatable analogy using everyday objects

        Use simple, clear language avoiding technical terms

        Include 2-3 interactive examples that demonstrate the concept

        Add fun facts that will spark curiosity

        End with simple questions to check understanding

        Keep the explanation brief (100-150 words)



        Structure your explanation as:

        

        Opening analogy

        Main explanation with examples

        Interactive "What if?" scenarios

        Fun facts about quantum entanglement

        Check-for-understanding questions



        Remember to maintain an enthusiastic and encouraging tone throughout the explanation.

        

        Output example:

        Imagine you have two special pairs of socks. When you put one sock in your room and the other sock in the kitchen, 

        something magical happens! Whatever happens to one sock instantly affects the other sock. 

        If you turn one sock inside out, the other sock automatically turns inside out too, no matter how far apart they are!



        Example 2:

        {{prompt}}: "Write a function to calculate the Fibonacci sequence up to n terms."

        

        *thought_process*:

        - **Main goal of the prompt:** Create a programming function that generates Fibonacci numbers

        - **Persona:** Programming expert

        - **Optimal output length:** Medium (150-200 words including code)

        - **Most convenient output format:** Code snippet with explanatory comments

        - **Specific requirements:** Function must accept parameter n for sequence length

        - **Suggested improvements:** 

            - Specify programming language

            - Clarify if 0 should be included as first term

            - Define expected handling of negative inputs

        - **One-shot prompting:** 

        

        *output*:

        As an expert programmer, please create a well-documented function to generate the Fibonacci sequence. 

        

        Requirements:

        Accept a parameter 'n' specifying the number of terms to generate

        Handle edge cases (n <= 0, n == 1)

        Return the sequence as a list/array

        Include proper error handling

        Add comments explaining the logic



        Provide the implementation in Python, including:

        Function definition with docstring

        Input validation

        Core algorithm

        Example usage with outputs for n=5, n=1, and n=0



        For reference, the sequence should start with [0, 1, ...] where each subsequent number is the sum of the previous two numbers.

        

        

        Now, analyze the following prompt then return only the generated *output*:

        {{prompt}}: {input_prompt}

        """

        return await self.call_llm(analysis_and_expansion_prompt)

    
    async def decompose_and_add_reasoning(self, expanded_prompt):
        decomposition_and_reasoning_prompt = f"""

        You are a highly capable AI assistant tasked with improving complex task execution. 

        Analyze the provided {{prompt}}, and use it to generate the following output:

        

        - **Subtasks decomposition:** Break down the task described in the prompt into manageable and specific subtasks that the AI model needs to address.

        - **Chain-of-thought reasoning:** For subtasks that involve critical thinking or complex steps, add reasoning using a step-by-step approach to improve decision-making and output quality.

        - **Success criteria:** Define what constitutes a successful completion for each subtask, ensuring clear guidance for expected results.



        Return the following structured output for each subtask:



        1. **Subtask description**: Describe a specific subtask.

        2. **Reasoning**: Provide reasoning or explanation for why this subtask is essential or how it should be approached.

        3. **Success criteria**: Define what successful completion looks like for this subtask.



        Example 1:

        {{Prompt}}: "Explain how machine learning models are evaluated using cross-validation."



        ##THOUGHT PROCESS##

        *Subtask 1*:

        - **Description**: Define cross-validation and its purpose.

        - **Reasoning**: Clarifying the concept ensures the reader understands the basic mechanism behind model evaluation.

        - **Success criteria**: The explanation should include a clear definition of cross-validation and its role in assessing model performance.

        *Subtask 2*:

        - **Description**: Describe how cross-validation splits data into training and validation sets.

        - **Reasoning**: Explaining the split is crucial to understanding how models are validated and tested for generalization.

        - **Success criteria**: A proper explanation of k-fold cross-validation with an illustration of how data is split.

        *Subtask 3*:

        - **Description**: Discuss how cross-validation results are averaged to provide a final evaluation metric.

        - **Reasoning**: Averaging results helps mitigate the variance in performance due to different training/validation splits.

        - **Success criteria**: The output should clearly explain how the final model evaluation is derived from multiple iterations of cross-validation.



        Now, analyze the following expanded prompt and return the subtasks, reasoning, and success criteria.

        Prompt: {expanded_prompt}

        """
        return await self.call_llm(decomposition_and_reasoning_prompt)

    
    
    async def suggest_enhancements(self, input_prompt, tools_dict={}):
        enhancement_suggestion_prompt = f"""

        You are a highly intelligent assistant specialized in reference suggestion and tool integration.

        Analyze the provided {{input_prompt}} and the available {{tools_dict}} to recommend enhancements:



        - **Reference necessity:** Determine if additional reference materials would benefit the task execution (e.g., websites, documentations, books, articles, etc.)

        - **Tool applicability:** Evaluate if any available tools could enhance efficiency or accuracy

        - **Integration complexity:** Assess the effort required to incorporate suggested resources

        - **Expected impact:** Estimate the potential improvement in output quality

        

        If enhancements are warranted, provide structured recommendations in this format:

        

        ##REFERENCE SUGGESTIONS##

        (Only if applicable, maximum 3)

        - Reference name/type

        - Purpose: How it enhances the output

        - Integration: How to incorporate it

        

        ##TOOL SUGGESTIONS##

        (Only if applicable, maximum 3)

        - Tool name from tools_dict

        - Purpose: How it improves the task

        - Integration: How to implement it

        

        If no enhancements would significantly improve the output, return an empty string ""



        Example 1:

        {{input_prompt}}: "Write a Python function to detect faces in images using computer vision."

        {{tools_dict}}: {{}}

        *output*:

        ##REFERENCE SUGGESTIONS##

        - OpenCV Face Detection Documentation

          Purpose: Provides implementation details and best practices

          Integration: Reference for optimal parameter settings and cascade classifier usage        

        

        Now, analyze the following prompt and tools, then return only the generated *output*:

        {{input_prompt}}: {input_prompt}

        {{tools_dict}}: {tools_dict}

        """
        return await self.call_llm(enhancement_suggestion_prompt)
    
    
    async def assemble_prompt(self, components):
        expanded_prompt = components.get("expanded_prompt", "")
        decomposition_and_reasoninng = components.get("decomposition_and_reasoninng", "")
        suggested_enhancements = components.get("suggested_enhancements", "")
        
        output_prompt = (
            f"{expanded_prompt}\n\n"
            f"{suggested_enhancements}\n\n"
            f"{decomposition_and_reasoninng}"
        )
        return output_prompt
    
    
    async def enhance_prompt(self, input_prompt):
        """Main method to enhance a prompt"""
        tools_dict = {}
        
        expanded_prompt = await self.analyze_and_expand_input(input_prompt)
        suggested_enhancements = await self.suggest_enhancements(input_prompt, tools_dict)
        decomposition_and_reasoning = await self.decompose_and_add_reasoning(expanded_prompt)
        
        components = {
            "expanded_prompt": expanded_prompt,
            "decomposition_and_reasoninng": decomposition_and_reasoning,
            "suggested_enhancements": suggested_enhancements
        }
        
        output_prompt = await self.assemble_prompt(components)
        
        return output_prompt