Spaces:
Running
Running
Upload 7 files
Browse files- Blueprint.md +409 -0
- chatbot.py +165 -0
- config.py +49 -0
- data_models.py +61 -0
- main.py +194 -0
- requirements.txt +6 -0
- utils.py +456 -0
Blueprint.md
ADDED
@@ -0,0 +1,409 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Technical Blueprint for Innovative Idea Generator Chatbot (Updated)
|
2 |
+
|
3 |
+
## Table of Contents
|
4 |
+
|
5 |
+
1. [Introduction](#introduction)
|
6 |
+
2. [High-Level Overview](#high-level-overview)
|
7 |
+
- [Purpose and Goals](#purpose-and-goals)
|
8 |
+
- [Key Functionalities](#key-functionalities)
|
9 |
+
3. [System Architecture](#system-architecture)
|
10 |
+
- [Components](#components)
|
11 |
+
- [Data Flow](#data-flow)
|
12 |
+
4. [Detailed Module Design](#detailed-module-design)
|
13 |
+
- [Chatbot Interaction Module](#chatbot-interaction-module)
|
14 |
+
- [Stage-Based Interaction](#stage-based-interaction)
|
15 |
+
- [Dynamic Follow-ups](#dynamic-follow-ups)
|
16 |
+
- [Context Preservation](#context-preservation)
|
17 |
+
- [Data Collection and Refinement Module](#data-collection-and-refinement-module)
|
18 |
+
- [Input Parsing](#input-parsing)
|
19 |
+
- [Data Storage](#data-storage)
|
20 |
+
- [Data Refinement](#data-refinement)
|
21 |
+
- [Stage Management Module](#stage-management-module)
|
22 |
+
- [Stage Buttons Interface](#stage-buttons-interface)
|
23 |
+
- [Function Modularity](#function-modularity)
|
24 |
+
- [Web Search Integration Module](#web-search-integration-module)
|
25 |
+
- [LLM-Triggered Web Searches](#llm-triggered-web-searches)
|
26 |
+
- [User-Triggered Web Searches](#user-triggered-web-searches)
|
27 |
+
- [Database Management Module](#database-management-module)
|
28 |
+
- [Data Storage Format](#data-storage-format)
|
29 |
+
- [Dynamic Editing](#dynamic-editing)
|
30 |
+
5. [Implementation Details](#implementation-details)
|
31 |
+
- [Python and Gradio Usage](#python-and-gradio-usage)
|
32 |
+
- [Module and Function Organization](#module-and-function-organization)
|
33 |
+
- [Error Handling and Validation](#error-handling-and-validation)
|
34 |
+
- [LLM Context and Memory Management](#llm-context-and-memory-management)
|
35 |
+
- [User Interface Enhancements](#user-interface-enhancements)
|
36 |
+
6. [Additional Considerations](#additional-considerations)
|
37 |
+
- [Scalability and Extensibility](#scalability-and-extensibility)
|
38 |
+
- [Security and Privacy](#security-and-privacy)
|
39 |
+
- [Testing and Validation](#testing-and-validation)
|
40 |
+
7. [Conclusion](#conclusion)
|
41 |
+
|
42 |
+
---
|
43 |
+
|
44 |
+
## Introduction
|
45 |
+
|
46 |
+
This blueprint outlines the technical design for the **Innovative Idea Generator Chatbot**, an application aimed at transforming user ideas into well-defined project proposals ready for prototyping. The chatbot guides users through a structured, stage-based workflow, refining their inputs, and dynamically storing data for further editing and retrieval. The application is developed using **Python** and **Gradio**, adhering strictly to Python-based frameworks without the use of JavaScript, Next.js, or similar technologies.
|
47 |
+
|
48 |
+
---
|
49 |
+
|
50 |
+
## High-Level Overview
|
51 |
+
|
52 |
+
### Purpose and Goals
|
53 |
+
|
54 |
+
- **Objective**: Assist users in refining raw ideas into structured project proposals.
|
55 |
+
- **Outcome**: Generate a comprehensive proposal by collecting, refining, and storing user inputs through guided, stage-by-stage interactions.
|
56 |
+
|
57 |
+
### Key Functionalities
|
58 |
+
|
59 |
+
1. **Stage-Based Interaction**: Users navigate through the idea development process using individual stage buttons.
|
60 |
+
2. **Dynamic Follow-ups**: Trigger additional questions based on user responses for clarification.
|
61 |
+
3. **Data Refinement**: Rewrite user inputs for clarity and store them dynamically.
|
62 |
+
4. **Context Preservation**: Maintain conversation history for seamless interactions.
|
63 |
+
5. **Web Search Integration**: Allow both LLM and users to perform web searches during the interaction.
|
64 |
+
6. **Data Storage and Editing**: Store all collected data in a dynamic database accessible for modifications.
|
65 |
+
7. **Stage Navigation with Buttons**: Replace progress tracking bar with a checklist of clickable stage buttons.
|
66 |
+
8. **Stage-Specific Processing**: LLM processes one stage at a time based on user-activated buttons.
|
67 |
+
9. **Customizable AI Settings**: Allow users to select models and adjust generation parameters.
|
68 |
+
10. **API Key Management**: Enable users to securely input their Hugging Face API keys for model interactions.
|
69 |
+
|
70 |
+
---
|
71 |
+
|
72 |
+
## System Architecture
|
73 |
+
|
74 |
+
### Components
|
75 |
+
|
76 |
+
1. **User Interface (UI)**: Built with Gradio, providing a stage-based button interface and corresponding text fields.
|
77 |
+
2. **Chatbot Engine**: Manages conversations, including stage-specific prompts and response handling.
|
78 |
+
3. **Language Model (LLM) Interaction**: Utilizes an LLM for generating responses and processing inputs.
|
79 |
+
4. **Data Storage**: A database (SQL or CSV) for storing refined user inputs and conversation history.
|
80 |
+
5. **Web Search Module**: Integrates web search capabilities using APIs (e.g., DuckDuckGo Search).
|
81 |
+
6. **API Management Module**: Handles secure input and storage of user-provided API keys.
|
82 |
+
7. **Stage Management Interface**: Manages the display and interaction of stage buttons and corresponding text fields.
|
83 |
+
|
84 |
+
### Data Flow
|
85 |
+
|
86 |
+
1. **User Activation**: User clicks a stage button to initiate a specific stage.
|
87 |
+
2. **LLM Processing**: Chatbot focuses on the selected stage, prompting the user for relevant information.
|
88 |
+
3. **User Input**: User provides input for the stage.
|
89 |
+
4. **Data Refinement**: LLM refines the input for clarity and coherence.
|
90 |
+
5. **Form Population**: User presses the 'Fill Out Form' button to populate the corresponding text field with refined data.
|
91 |
+
6. **Data Storage**: Refined inputs are stored in the database.
|
92 |
+
7. **Web Search**: Triggered by the LLM or user, with results incorporated into the conversation.
|
93 |
+
8. **Stage Completion**: User marks the stage as complete before moving to the next stage.
|
94 |
+
9. **Feedback Loop**: Process repeats until all stages are completed.
|
95 |
+
|
96 |
+
---
|
97 |
+
|
98 |
+
## Detailed Module Design
|
99 |
+
|
100 |
+
### Chatbot Interaction Module
|
101 |
+
|
102 |
+
#### Stage-Based Interaction
|
103 |
+
|
104 |
+
- **Stage Buttons**: Ten individual buttons represent each main question/stage. Users click these buttons to activate and work on specific stages.
|
105 |
+
- **Exclusive Focus**: Upon activation of a stage button (e.g., 'Idea Name'), the LLM concentrates solely on tasks related to that stage.
|
106 |
+
- **Sequential Processing**: Users can navigate stages in any order, allowing flexibility in the workflow.
|
107 |
+
|
108 |
+
#### Dynamic Follow-ups
|
109 |
+
|
110 |
+
- **Conditional Questions**: Based on user responses within a stage, the chatbot may ask additional questions for further clarification.
|
111 |
+
- **LLM Analysis**: The LLM analyzes responses to determine if more information is needed.
|
112 |
+
- **Implementation**:
|
113 |
+
- Use conditional logic to assess the completeness of user inputs.
|
114 |
+
- Trigger follow-up prompts when necessary to ensure comprehensive data collection.
|
115 |
+
|
116 |
+
#### Context Preservation
|
117 |
+
|
118 |
+
- **Conversation History**: Maintain a log of all interactions to provide context for each stage.
|
119 |
+
- **LLM Access**: Pass relevant conversation history to the LLM for consistent and informed responses.
|
120 |
+
- **Implementation**:
|
121 |
+
- Utilize a list or database to store message histories.
|
122 |
+
- Ensure that the LLM receives pertinent history relevant to the current stage without exceeding token limits.
|
123 |
+
|
124 |
+
### Data Collection and Refinement Module
|
125 |
+
|
126 |
+
#### Input Parsing
|
127 |
+
|
128 |
+
- **Structured Data Extraction**: Parse LLM responses to extract relevant information specific to each stage.
|
129 |
+
- **Tags and Markers**: Use specific markers (e.g., `<form_data></form_data>`) to delineate structured data within responses.
|
130 |
+
|
131 |
+
#### Data Storage
|
132 |
+
|
133 |
+
- **Database Choice**: Utilize SQL or CSV files for robust data storage.
|
134 |
+
- **Dynamic Updates**: Allow real-time updates to the stored data as users complete or modify stages.
|
135 |
+
- **Implementation**:
|
136 |
+
- Define a data model using Pydantic or similar for validation.
|
137 |
+
- Implement functions to read and write data to the database seamlessly.
|
138 |
+
|
139 |
+
#### Data Refinement
|
140 |
+
|
141 |
+
- **LLM Rewriting**: The LLM refines user inputs for clarity, coherence, and conciseness within each stage.
|
142 |
+
- **Validation**: Ensure the refined data aligns with the expected format and requirements of the stage.
|
143 |
+
- **Implementation**:
|
144 |
+
- Employ the LLM to generate refined versions of user inputs.
|
145 |
+
- Update the database with the refined data upon user confirmation.
|
146 |
+
|
147 |
+
### Stage Management Module
|
148 |
+
|
149 |
+
#### Stage Buttons Interface
|
150 |
+
|
151 |
+
- **Checklist of Stages**: Replace the traditional progress tracking bar with a checklist comprising individual stage buttons.
|
152 |
+
- **User Activation**: Users manually activate each stage by clicking the corresponding button, initiating focused processing by the LLM.
|
153 |
+
- **'Fill Out Form' Button**: After completing a stage, users press the 'Fill Out Form' button to populate the associated text field with refined data.
|
154 |
+
- **Implementation**:
|
155 |
+
- Design the UI to display ten stage buttons, each linked to a specific question.
|
156 |
+
- Ensure that each button triggers the LLM to handle only the tasks pertinent to that stage.
|
157 |
+
|
158 |
+
#### Function Modularity
|
159 |
+
|
160 |
+
- **Compartmentalization**: Each stage is implemented as a separate function or class method to ensure modularity.
|
161 |
+
- **Independent Modification**: Allows individual stages to be updated or modified without impacting others.
|
162 |
+
- **Implementation**:
|
163 |
+
- Define separate methods for each stage within the chatbot class.
|
164 |
+
- Utilize inheritance or composition for shared functionalities across stages.
|
165 |
+
|
166 |
+
### Web Search Integration Module
|
167 |
+
|
168 |
+
#### LLM-Triggered Web Searches
|
169 |
+
|
170 |
+
- **Automatic Searches**: The LLM determines when external information is necessary and triggers web searches accordingly.
|
171 |
+
- **Search Execution**: Perform searches using APIs and integrate the results into the conversation context.
|
172 |
+
- **Implementation**:
|
173 |
+
- LLM outputs a special token or command when a web search is needed.
|
174 |
+
- Chatbot captures this command and performs the search using the designated API.
|
175 |
+
|
176 |
+
#### User-Triggered Web Searches
|
177 |
+
|
178 |
+
- **User Commands**: Users can initiate searches by typing '@' followed by their query.
|
179 |
+
- **Query Optimization**: The LLM rewrites user queries to enhance search effectiveness.
|
180 |
+
- **Implementation**:
|
181 |
+
- Detect messages starting with '@' to identify user-initiated searches.
|
182 |
+
- Pass the query through the LLM for optimization before performing the search.
|
183 |
+
|
184 |
+
### Database Management Module
|
185 |
+
|
186 |
+
#### Data Storage Format
|
187 |
+
|
188 |
+
- **Structured Data**: Store data in well-defined tables or a structured SQLite database to ensure data integrity.
|
189 |
+
- **Fields**: Include all necessary fields corresponding to the ten main questions/stages.
|
190 |
+
- **Implementation**:
|
191 |
+
- Define a comprehensive schema for the SQL database.
|
192 |
+
- Use an Object-Relational Mapping (ORM) tool like SQLAlchemy for efficient database interactions.
|
193 |
+
|
194 |
+
#### Dynamic Editing
|
195 |
+
|
196 |
+
- **User Modifications**: Allow users to edit previous inputs through the UI, updating the corresponding text fields.
|
197 |
+
- **Real-Time Updates**: Reflect changes immediately in the database to maintain data consistency.
|
198 |
+
- **Implementation**:
|
199 |
+
- Provide editable text fields beneath each stage button.
|
200 |
+
- Implement functions to update the database upon user edits, ensuring that the refined data remains accurate and up-to-date.
|
201 |
+
|
202 |
+
---
|
203 |
+
|
204 |
+
## Implementation Details
|
205 |
+
|
206 |
+
### Python and Gradio Usage
|
207 |
+
|
208 |
+
- **Framework**: Utilize Gradio for the UI, providing a web-based interface with stage buttons and corresponding text fields.
|
209 |
+
- **Libraries**:
|
210 |
+
- **LLM Interaction**: Use `huggingface_hub` for LLM API calls.
|
211 |
+
- **Data Models**: Use `pydantic` for data validation and modeling.
|
212 |
+
- **Web Search**: Use `duckduckgo_search` API for web searches.
|
213 |
+
- **Environment Variables**: Use `python-dotenv` for managing API keys and configuration.
|
214 |
+
|
215 |
+
### Module and Function Organization
|
216 |
+
|
217 |
+
- **Main Modules**:
|
218 |
+
- `main.py`: Entry point of the application.
|
219 |
+
- `chatbot.py`: Contains the `InnovativeIdeaChatbot` class and related functions.
|
220 |
+
- `data_models.py`: Defines data models using Pydantic.
|
221 |
+
- `utils.py`: Utility functions for parsing, web search, etc.
|
222 |
+
- `config.py`: Configuration settings and constants.
|
223 |
+
- **Function Structure**:
|
224 |
+
- Each function should have clear input/output parameters.
|
225 |
+
- Include docstrings with type hints for clarity and maintainability.
|
226 |
+
- Ensure that each stage's function handles only its specific tasks to maintain modularity.
|
227 |
+
|
228 |
+
### Error Handling and Validation
|
229 |
+
|
230 |
+
- **User Input Validation**: Check for empty, invalid, or malformed inputs before processing.
|
231 |
+
- **API Error Handling**: Catch exceptions from API calls and provide user-friendly error messages or prompts.
|
232 |
+
- **Data Validation**: Use Pydantic models to validate data before storage to ensure data integrity.
|
233 |
+
- **Implementation**:
|
234 |
+
- Utilize try-except blocks around critical sections, especially around API interactions.
|
235 |
+
- Provide default values or prompts to guide users in case of errors or invalid inputs.
|
236 |
+
- Implement validation checks before updating the database with refined data.
|
237 |
+
|
238 |
+
### LLM Context and Memory Management
|
239 |
+
|
240 |
+
- **Conversation Length**: Manage the size of the conversation history to stay within LLM token limits, ensuring efficient processing.
|
241 |
+
- **Contextual Responses**: Ensure the LLM receives sufficient context relevant to the current stage without overwhelming it with unnecessary information.
|
242 |
+
- **Implementation**:
|
243 |
+
- Implement a sliding window mechanism to include only recent and relevant messages in the LLM prompt.
|
244 |
+
- Summarize older parts of the conversation if necessary to maintain context within token limits.
|
245 |
+
- Ensure that each stage's context is isolated to prevent cross-stage contamination.
|
246 |
+
|
247 |
+
### User Interface Enhancements
|
248 |
+
|
249 |
+
- **Stage Buttons**: Design intuitive and clearly labeled buttons for each of the ten stages, allowing easy navigation.
|
250 |
+
- **Text Fields**: Place editable text fields beneath each stage button to display and allow modifications of the refined data.
|
251 |
+
- **'Fill Out Form' Button**: Include a dedicated button for users to populate the corresponding text field with the refined data after completing a stage.
|
252 |
+
- **Visual Indicators**: Implement visual cues (e.g., color changes, checkmarks) to indicate the completion status of each stage.
|
253 |
+
- **Responsive Design**: Ensure the UI is responsive and user-friendly across different devices and screen sizes.
|
254 |
+
- **Implementation**:
|
255 |
+
- Utilize Gradio's layout features to arrange buttons and text fields logically.
|
256 |
+
- Incorporate CSS styling within Gradio to enhance the visual appeal and usability of the interface.
|
257 |
+
- Ensure that the UI updates dynamically based on user interactions and stage completions.
|
258 |
+
|
259 |
+
### API Key Management
|
260 |
+
|
261 |
+
- **Secure Input**: Allow users to input their Hugging Face API keys securely through the UI.
|
262 |
+
- **Environment Variables**: Store API keys using environment variables to prevent exposure and enhance security.
|
263 |
+
- **Implementation**:
|
264 |
+
- Provide a secure input field in the UI for users to enter their API keys.
|
265 |
+
- Utilize `python-dotenv` to manage and access API keys within the application without hardcoding them.
|
266 |
+
- Ensure that API keys are never exposed in logs or error messages.
|
267 |
+
|
268 |
+
---
|
269 |
+
|
270 |
+
# Appendices
|
271 |
+
|
272 |
+
## Appendix A: Data Model Definition
|
273 |
+
|
274 |
+
### InnovativeIdeaForm (Pydantic BaseModel)
|
275 |
+
|
276 |
+
Defines the structure for storing refined user inputs.
|
277 |
+
|
278 |
+
```python
|
279 |
+
from pydantic import BaseModel, Field
|
280 |
+
from typing import List, Optional
|
281 |
+
|
282 |
+
class InnovativeIdeaForm(BaseModel):
|
283 |
+
idea_name: Optional[str] = Field(None, description="Name of the innovative idea")
|
284 |
+
idea_overview: Optional[str] = Field(None, description="Simple overview of the idea")
|
285 |
+
problem_solution: Optional[str] = Field(None, description="Customer problem and how the idea addresses it")
|
286 |
+
target_customers: Optional[str] = Field(None, description="Potential customers and markets")
|
287 |
+
market_value: Optional[str] = Field(None, description="Estimated market value")
|
288 |
+
existing_solutions: Optional[str] = Field(None, description="Similar existing ideas or products")
|
289 |
+
unique_value: Optional[str] = Field(None, description="How the idea is better or different")
|
290 |
+
technical_challenges: Optional[str] = Field(None, description="Difficult technical problems")
|
291 |
+
legal_barriers: Optional[str] = Field(None, description="Possible legal issues")
|
292 |
+
data_dependencies: Optional[str] = Field(None, description="Required data types")
|
293 |
+
team_roles: Optional[List[str]] = Field(None, description="Required job roles")
|
294 |
+
timeline: Optional[str] = Field(None, description="Estimated time to build main components")
|
295 |
+
additional_info: Optional[str] = Field(None, description="Any additional information")
|
296 |
+
```
|
297 |
+
|
298 |
+
## Appendix B: Function Signatures
|
299 |
+
|
300 |
+
### Chatbot Class Methods
|
301 |
+
|
302 |
+
```python
|
303 |
+
from typing import List, Dict, Tuple, Optional, Union
|
304 |
+
|
305 |
+
class InnovativeIdeaChatbot:
|
306 |
+
def __init__(self):
|
307 |
+
"""
|
308 |
+
Initializes the chatbot with necessary configurations and data storage.
|
309 |
+
"""
|
310 |
+
pass
|
311 |
+
|
312 |
+
def get_initial_greeting(self) -> str:
|
313 |
+
"""
|
314 |
+
Returns the initial greeting message to the user.
|
315 |
+
"""
|
316 |
+
pass
|
317 |
+
|
318 |
+
def activate_stage(self, stage_name: str) -> Optional[str]:
|
319 |
+
"""
|
320 |
+
Activates the specified stage and returns the prompt for that stage.
|
321 |
+
|
322 |
+
Args:
|
323 |
+
stage_name (str): The name of the stage to activate.
|
324 |
+
|
325 |
+
Returns:
|
326 |
+
Optional[str]: The prompt message for the activated stage.
|
327 |
+
"""
|
328 |
+
pass
|
329 |
+
|
330 |
+
def process_stage_input(self, stage_name: str, message: str) -> Tuple[str, Optional[str]]:
|
331 |
+
"""
|
332 |
+
Processes the user's input for a specific stage and returns the refined data.
|
333 |
+
|
334 |
+
Args:
|
335 |
+
stage_name (str): The name of the current stage.
|
336 |
+
message (str): The user's input message.
|
337 |
+
|
338 |
+
Returns:
|
339 |
+
Tuple[str, Optional[str]]: A tuple containing the refined data and an optional follow-up prompt.
|
340 |
+
"""
|
341 |
+
pass
|
342 |
+
|
343 |
+
def fill_out_form(self, stage_name: str) -> Optional[str]:
|
344 |
+
"""
|
345 |
+
Populates the corresponding text field with refined data for the specified stage.
|
346 |
+
|
347 |
+
Args:
|
348 |
+
stage_name (str): The name of the stage to fill out.
|
349 |
+
|
350 |
+
Returns:
|
351 |
+
Optional[str]: The refined data to be displayed in the text field.
|
352 |
+
"""
|
353 |
+
pass
|
354 |
+
|
355 |
+
def update_idea_form(self, stage_name: str, form_data: str):
|
356 |
+
"""
|
357 |
+
Updates the idea form with the provided refined data for a specific stage.
|
358 |
+
|
359 |
+
Args:
|
360 |
+
stage_name (str): The name of the stage being updated.
|
361 |
+
form_data (str): The refined data to update in the form.
|
362 |
+
"""
|
363 |
+
pass
|
364 |
+
|
365 |
+
def reset(self):
|
366 |
+
"""
|
367 |
+
Resets the chatbot state for a new session, clearing all stored data and history.
|
368 |
+
"""
|
369 |
+
pass
|
370 |
+
```
|
371 |
+
|
372 |
+
## Appendix C: Sample System Prompt Template
|
373 |
+
|
374 |
+
```text
|
375 |
+
You are an AI assistant named Myamoto, designed to help users refine their innovative ideas. Your task is to guide them through the ideation process, stage by stage, asking relevant questions and providing insightful feedback at each stage. Be encouraging, creative, and analytical in your responses. Remember to:
|
376 |
+
|
377 |
+
1. Analyze the user's input carefully and extract relevant information for the current stage.
|
378 |
+
2. Provide constructive feedback and suggestions to improve the idea.
|
379 |
+
3. Ask specific, targeted follow-up questions to gather more details if needed.
|
380 |
+
4. Offer creative ideas or alternatives to enhance the user's concept.
|
381 |
+
5. Maintain a supportive and enthusiastic tone throughout the conversation.
|
382 |
+
6. When you feel the current stage has been thoroughly explored, explicitly state "stage complete" or "ready to move on" in your response.
|
383 |
+
7. Break down your thinking process into steps, enclosed in <step></step> tags.
|
384 |
+
8. Provide a reflection on your thought process, enclosed in <reflection></reflection> tags.
|
385 |
+
9. For each stage, provide a refined, clear, and concise version of the user's input. This refined version should capture the essence of the user's idea while improving its clarity and coherence.
|
386 |
+
10. If you think additional information from a web search might be helpful, suggest it to the user. Ask them to use '@' followed by their search query to perform a web search.
|
387 |
+
11. Always include a <form_data></form_data> section in your response with the extracted information for the current stage.
|
388 |
+
12. Be explicit when a stage is complete and indicate that you're ready to move to the next stage.
|
389 |
+
|
390 |
+
Please format your response as follows:
|
391 |
+
<answer>
|
392 |
+
[Your main response here, including follow-up questions and web search suggestions if applicable]
|
393 |
+
[If the stage is complete, include a clear statement like "This stage is now complete. We're ready to move on to the next stage."]
|
394 |
+
</answer>
|
395 |
+
|
396 |
+
<form_data>
|
397 |
+
[Extracted information for the current stage in a structured format]
|
398 |
+
</form_data>
|
399 |
+
|
400 |
+
<reflection>
|
401 |
+
[Your reflection on the thought process]
|
402 |
+
</reflection>
|
403 |
+
|
404 |
+
<step>[Step 1 of your thinking process]</step>
|
405 |
+
<step>[Step 2 of your thinking process]</step>
|
406 |
+
...
|
407 |
+
|
408 |
+
Current stage: {{current_stage}}
|
409 |
+
```
|
chatbot.py
ADDED
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import List, Tuple, Dict, Any, Optional
|
2 |
+
from data_models import IdeaForm, IDEA_STAGES
|
3 |
+
from config import DEFAULT_SYSTEM_PROMPT, STAGES
|
4 |
+
from utils import (
|
5 |
+
get_llm_response, extract_form_data, save_idea_to_database,
|
6 |
+
load_idea_from_database, update_idea_in_database,
|
7 |
+
get_db, clear_database, init_db, create_tables,
|
8 |
+
perform_web_search, optimize_search_query,
|
9 |
+
SessionLocal, InnovativeIdea
|
10 |
+
)
|
11 |
+
|
12 |
+
class InnovativeIdeaChatbot:
|
13 |
+
def __init__(self):
|
14 |
+
create_tables()
|
15 |
+
init_db()
|
16 |
+
self.idea_form = IdeaForm()
|
17 |
+
self.chat_history = []
|
18 |
+
self.idea_id = None
|
19 |
+
self.db = SessionLocal()
|
20 |
+
self.current_stage = None
|
21 |
+
self.api_key = None
|
22 |
+
self.add_system_message(self.get_initial_greeting())
|
23 |
+
|
24 |
+
def __del__(self):
|
25 |
+
if hasattr(self, 'db'):
|
26 |
+
self.db.close()
|
27 |
+
|
28 |
+
def get_initial_greeting(self) -> str:
|
29 |
+
return "Welcome to the Innovative Idea Generator! Please select a stage to begin."
|
30 |
+
|
31 |
+
def add_system_message(self, message: str):
|
32 |
+
self.chat_history.append(("System", message))
|
33 |
+
|
34 |
+
def set_api_key(self, api_key: str):
|
35 |
+
self.api_key = api_key
|
36 |
+
|
37 |
+
def activate_stage(self, stage_name: str) -> Optional[str]:
|
38 |
+
self.current_stage = stage_name
|
39 |
+
for stage in STAGES:
|
40 |
+
if stage["name"] == stage_name:
|
41 |
+
return f"Let's work on the '{stage_name}' stage. {stage['question']}"
|
42 |
+
return None
|
43 |
+
|
44 |
+
def process_stage_input(self, stage_name: str, message: str, model: str, system_prompt: str, thinking_budget: int) -> Tuple[List[Tuple[str, str]], Dict[str, Any]]:
|
45 |
+
if self.current_stage != stage_name:
|
46 |
+
activation_message = self.activate_stage(stage_name)
|
47 |
+
if activation_message is None:
|
48 |
+
error_message = f"Error: Unable to activate stage '{stage_name}'. Please check if the stage name is correct."
|
49 |
+
self.chat_history.append(("System", error_message))
|
50 |
+
return self.chat_history, self.idea_form.dict()
|
51 |
+
self.chat_history.append(("System", activation_message))
|
52 |
+
|
53 |
+
# Check for web search request
|
54 |
+
if message.startswith('@'):
|
55 |
+
search_query = message[1:].strip()
|
56 |
+
optimized_query = optimize_search_query(search_query, model)
|
57 |
+
search_results = perform_web_search(optimized_query)
|
58 |
+
self.chat_history.append(("Human", message))
|
59 |
+
self.chat_history.append(("AI", f"Here are the search results for '{optimized_query}':\n\n{search_results}"))
|
60 |
+
return self.chat_history, self.idea_form.dict()
|
61 |
+
|
62 |
+
# Generate the prompt for the current stage
|
63 |
+
stage_prompt = self.generate_prompt_for_stage(stage_name)
|
64 |
+
|
65 |
+
# Combine the user's input with the stage prompt
|
66 |
+
combined_prompt = f"{stage_prompt}\n\nUser input: {message}"
|
67 |
+
|
68 |
+
# Get LLM response
|
69 |
+
llm_response = get_llm_response(combined_prompt, model, thinking_budget, self.api_key)
|
70 |
+
|
71 |
+
# Add the interaction to chat history
|
72 |
+
self.chat_history.append(("Human", message))
|
73 |
+
self.chat_history.append(("AI", llm_response))
|
74 |
+
|
75 |
+
# Extract form data from the LLM response
|
76 |
+
form_data = extract_form_data(llm_response)
|
77 |
+
|
78 |
+
# Update the idea form
|
79 |
+
if stage_name in form_data:
|
80 |
+
setattr(self.idea_form, stage_name.lower().replace(" ", "_"), form_data[stage_name])
|
81 |
+
|
82 |
+
return self.chat_history, self.idea_form.dict()
|
83 |
+
|
84 |
+
def fill_out_form(self, current_stage: str, model: str, thinking_budget: int) -> Dict[str, str]:
|
85 |
+
form_data = {}
|
86 |
+
for stage in STAGES:
|
87 |
+
stage_name = stage["name"]
|
88 |
+
if stage_name == current_stage:
|
89 |
+
# Generate new data for the current stage
|
90 |
+
form_data[stage_name] = self.generate_form_data(stage_name, model, thinking_budget)
|
91 |
+
else:
|
92 |
+
# Use existing data for other stages
|
93 |
+
form_data[stage_name] = getattr(self.idea_form, stage["field"], "")
|
94 |
+
|
95 |
+
# Update the idea form
|
96 |
+
for stage in STAGES:
|
97 |
+
setattr(self.idea_form, stage["field"], form_data[stage["name"]])
|
98 |
+
|
99 |
+
# Save to database
|
100 |
+
if self.idea_id:
|
101 |
+
update_idea_in_database(self.idea_id, self.idea_form, self.db)
|
102 |
+
else:
|
103 |
+
self.idea_id = save_idea_to_database(self.idea_form, self.db)
|
104 |
+
|
105 |
+
return form_data
|
106 |
+
|
107 |
+
def generate_prompt_for_stage(self, stage: str) -> str:
|
108 |
+
for s in STAGES:
|
109 |
+
if s["name"] == stage:
|
110 |
+
prompt_text = s.get('question') or s.get('description', '')
|
111 |
+
return f"We are currently working on the '{stage}' stage. {prompt_text}"
|
112 |
+
return f"We are currently working on the '{stage}' stage. Please provide relevant information."
|
113 |
+
|
114 |
+
def reset(self):
|
115 |
+
self.chat_history = []
|
116 |
+
self.idea_form = IdeaForm()
|
117 |
+
self.idea_id = None
|
118 |
+
self.current_stage = None
|
119 |
+
self.add_system_message(self.get_initial_greeting())
|
120 |
+
clear_database(self.db)
|
121 |
+
return self.chat_history, self.idea_form.dict()
|
122 |
+
|
123 |
+
def update_idea_form(self, stage_name: str, form_data: str):
|
124 |
+
setattr(self.idea_form, stage_name.lower().replace(" ", "_"), form_data)
|
125 |
+
if self.idea_id:
|
126 |
+
update_idea_in_database(self.idea_id, self.idea_form, self.db)
|
127 |
+
else:
|
128 |
+
self.idea_id = save_idea_to_database(self.idea_form, self.db)
|
129 |
+
|
130 |
+
def generate_form_data(self, stage: str, model: str, thinking_budget: int) -> str:
|
131 |
+
# Prepare the conversation history for the LLM
|
132 |
+
conversation = "\n".join([f"{role}: {message}" for role, message in self.chat_history])
|
133 |
+
|
134 |
+
prompt = f"""
|
135 |
+
Based on the following conversation, extract the relevant information for the '{stage}' stage of the innovative idea:
|
136 |
+
|
137 |
+
{conversation}
|
138 |
+
|
139 |
+
Please provide a concise summary for the '{stage}' stage, focusing only on the information relevant to this stage.
|
140 |
+
"""
|
141 |
+
|
142 |
+
# Get LLM response
|
143 |
+
llm_response = get_llm_response(prompt, model, thinking_budget, self.api_key)
|
144 |
+
|
145 |
+
# Extract form data from the LLM response
|
146 |
+
form_data = extract_form_data(llm_response)
|
147 |
+
|
148 |
+
return form_data.get(stage, "")
|
149 |
+
|
150 |
+
def start_over(self):
|
151 |
+
self.reset()
|
152 |
+
clear_database(self.db)
|
153 |
+
self.idea_id = None
|
154 |
+
|
155 |
+
# Reinitialize with a new empty idea
|
156 |
+
new_idea = InnovativeIdea()
|
157 |
+
self.db.add(new_idea)
|
158 |
+
self.db.commit()
|
159 |
+
self.idea_id = new_idea.id
|
160 |
+
|
161 |
+
self.idea_form = IdeaForm()
|
162 |
+
self.chat_history = []
|
163 |
+
self.add_system_message(self.get_initial_greeting())
|
164 |
+
|
165 |
+
return self.chat_history, self.idea_form.dict()
|
config.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
|
4 |
+
load_dotenv()
|
5 |
+
|
6 |
+
API_TOKEN = os.getenv("HUGGINGFACE_API_TOKEN")
|
7 |
+
|
8 |
+
MODELS = [
|
9 |
+
"NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
|
10 |
+
# Add other models here if needed
|
11 |
+
]
|
12 |
+
|
13 |
+
STAGES = [
|
14 |
+
{"name": "Idea Name", "field": "idea_name", "question": "Do you have a name for this idea?", "example": "Sharks with Laserbeams"},
|
15 |
+
{"name": "Idea Overview", "field": "idea_overview", "question": "Tell me about your idea, give a very simple overview as you might explain to younger child.", "example": "My idea is to attach laserbeams to sharks to create the ultimate evil weapon. The laserbeams are powered by a battery that are recharged by the shark's swimming motion. The laserbeams are used to attack enemy submarines."},
|
16 |
+
{"name": "Problem Solution", "field": "problem_solution", "question": "Tell me what Customer problem your idea addresses, and how does your idea address it?", "example": "Our customers' secret lairs are often attacked by submarines. If our clients had sharks with laserbeams they could attack and destroy the submarines, saving the secret lair from being discovered."},
|
17 |
+
{"name": "Target Customers", "field": "target_customers", "question": "What customers might be interested in this idea? Or is this a internal cost-savings / efficiency idea?", "example": "Evil geniuses, tyrannical dictators, rogue government agencies"},
|
18 |
+
{"name": "Market Value", "field": "market_value", "question": "What markets or industries is this idea for?", "example": "Defense Contractors, submarine manufacturers"},
|
19 |
+
{"name": "Existing Solutions", "field": "existing_solutions", "question": "What are some similar ideas or products that already exist today?", "example": "Nuclear Attack submarines and giant squids are somewhat similar to Shark with Laserbeams."},
|
20 |
+
{"name": "Unique Value", "field": "unique_value", "question": "How is your idea better or different?", "example": "Shark with Laserbeams are cheaper than Nuclear Attack submarines and the lasers are more powerful than squid tentacles."},
|
21 |
+
{"name": "Technical Challenges", "field": "technical_challenges", "question": "Are there any difficult technical problems with making this idea happen?", "example": "We would need to design a waterproof housing for the laser and batteries. We might need to experiment with how powerful lasers need to be when underwater in order to melt submarine steel hulls. We need to explore how to capture sharks and install the waterproof harnesses for the lasers."},
|
22 |
+
{"name": "Legal Barriers", "field": "legal_barriers", "question": "Any legal barriers?", "example": "We will need to obtain a weapons export license if we want to sell outside the United States."},
|
23 |
+
{"name": "Data Dependencies", "field": "data_dependencies", "question": "Any data dependencies?", "example": "We might need to get data on underwater motion vectors for creating the aiming mechanism for the lasers."},
|
24 |
+
{"name": "Team Roles", "field": "team_roles", "question": "What kind of people / job roles do you need to make this idea happen?", "example": "We will need marine biologists and fishermen for obtaining sharks. We will need electrical engineers, optical engineers and software engineers to create the laserbeam weapon. We will need project manager to help manage the budget and schedule. And we need a QA tester to ensure the laser is working underwater."},
|
25 |
+
{"name": "Timeline", "field": "timeline", "question": "About how long will it take to build the main components of your idea?", "example": "It will take a 2-3weeks to capture a shark. It will take 2-3 weeks to modify the harness and calibrate the laserbeam. I estimate it will take 3 months to train the shark to attack submarines."},
|
26 |
+
{"name": "Additional Info", "field": "additional_info", "question": "Anything else you'd want to add to help us understand and value your idea?", "example": "We might consider adding optional racing stripes or bioluminescent patterns ot the sharks as an upgrade with charge the customer for. We could explore a subscription model where we send the customers a new shark each quarter to replace sharks that age out of the program."}
|
27 |
+
]
|
28 |
+
|
29 |
+
DEFAULT_SYSTEM_PROMPT = """
|
30 |
+
You are Myamoto, an AI assistant designed to guide users through the innovative idea development process. Your task is to help refine and expand their ideas, focusing strictly on one stage at a time. Be encouraging, creative, and analytical in your responses. Remember to:
|
31 |
+
|
32 |
+
1. Analyze the user's input carefully and extract relevant information for the current stage only.
|
33 |
+
2. Provide constructive feedback and suggestions to improve the idea, specific to the current stage.
|
34 |
+
3. If the user's response is insufficient, ask follow-up questions to gather more details.
|
35 |
+
4. Do not move to the next stage automatically. The user must explicitly indicate when they want to move on.
|
36 |
+
5. Maintain a supportive and enthusiastic tone throughout the conversation.
|
37 |
+
6. Always include a <form_data></form_data> section in your response with the extracted information for the current stage.
|
38 |
+
7. If the user tries to skip ahead or provide information for future stages, gently redirect them to the current stage.
|
39 |
+
8. Use analogies, examples, or thought-provoking questions to help users think more deeply about their ideas.
|
40 |
+
9. When you feel the current stage has been thoroughly explored, explicitly state "stage complete" or "ready to move on" in your response.
|
41 |
+
10. Break down your thinking process into steps, enclosed in <step></step> tags.
|
42 |
+
11. Provide a reflection on your thought process, enclosed in <reflection></reflection> tags.
|
43 |
+
12. If you think additional information from a web search might be helpful, suggest it to the user. Ask them to use '@' followed by their search query to perform a web search.
|
44 |
+
|
45 |
+
Current stage: {current_stage}
|
46 |
+
Stage prompt: {stage_prompt}
|
47 |
+
"""
|
48 |
+
|
49 |
+
# Other configuration variables can be added here
|
data_models.py
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel, Field
|
2 |
+
from typing import List, Optional
|
3 |
+
from sqlalchemy import Column, Integer, String, Text
|
4 |
+
from sqlalchemy.ext.declarative import declarative_base
|
5 |
+
|
6 |
+
Base = declarative_base()
|
7 |
+
|
8 |
+
class IdeaStage(BaseModel):
|
9 |
+
name: str
|
10 |
+
field: str
|
11 |
+
question: str
|
12 |
+
example: str
|
13 |
+
|
14 |
+
class IdeaForm(BaseModel):
|
15 |
+
idea_name: Optional[str] = Field(None, description="Name of the innovative idea")
|
16 |
+
idea_overview: Optional[str] = Field(None, description="Simple overview of the idea")
|
17 |
+
problem_solution: Optional[str] = Field(None, description="Customer problem and how the idea addresses it")
|
18 |
+
target_customers: Optional[str] = Field(None, description="Potential customers and markets")
|
19 |
+
market_value: Optional[str] = Field(None, description="Estimated market value")
|
20 |
+
existing_solutions: Optional[str] = Field(None, description="Similar existing ideas or products")
|
21 |
+
unique_value: Optional[str] = Field(None, description="How the idea is better or different")
|
22 |
+
technical_challenges: Optional[str] = Field(None, description="Difficult technical problems")
|
23 |
+
legal_barriers: Optional[str] = Field(None, description="Possible legal issues")
|
24 |
+
data_dependencies: Optional[str] = Field(None, description="Required data types")
|
25 |
+
team_roles: Optional[List[str]] = Field(None, description="Required job roles")
|
26 |
+
timeline: Optional[str] = Field(None, description="Estimated time to build main components")
|
27 |
+
additional_info: Optional[str] = Field(None, description="Any additional information")
|
28 |
+
|
29 |
+
class InnovativeIdea(Base):
|
30 |
+
__tablename__ = 'innovative_ideas'
|
31 |
+
|
32 |
+
id = Column(Integer, primary_key=True, index=True)
|
33 |
+
idea_name = Column(String, index=True)
|
34 |
+
idea_overview = Column(Text)
|
35 |
+
problem_solution = Column(Text)
|
36 |
+
target_customers = Column(Text)
|
37 |
+
market_value = Column(String)
|
38 |
+
existing_solutions = Column(Text)
|
39 |
+
unique_value = Column(Text)
|
40 |
+
technical_challenges = Column(Text)
|
41 |
+
legal_barriers = Column(Text)
|
42 |
+
data_dependencies = Column(Text)
|
43 |
+
team_roles = Column(Text)
|
44 |
+
timeline = Column(Text)
|
45 |
+
additional_info = Column(Text)
|
46 |
+
|
47 |
+
IDEA_STAGES = [
|
48 |
+
IdeaStage(name="Idea Name", field="idea_name", question="Do you have a name for this idea?", example="Sharks with Laserbeams"),
|
49 |
+
IdeaStage(name="Idea Overview", field="idea_overview", question="Tell me about your idea, give a very simple overview as you might explain to younger child.", example="My idea is to attach laserbeams to sharks to create the ultimate evil weapon. The laserbeams are powered by a battery that are recharged by the shark's swimming motion. The laserbeams are used to attack enemy submarines."),
|
50 |
+
IdeaStage(name="Problem Solution", field="problem_solution", question="Tell me what Customer problem your idea addresses, and how does your idea address it?", example="Our customers' secret lairs are often attacked by submarines. If our clients had sharks with laserbeams they could attack and destroy the submarines, saving the secret lair from being discovered."),
|
51 |
+
IdeaStage(name="Target Customers", field="target_customers", question="What customers might be interested in this idea? Or is this a internal cost-savings / efficiency idea?", example="Evil geniuses, tyrannical dictators, rogue government agencies"),
|
52 |
+
IdeaStage(name="Market Value", field="market_value", question="What markets or industries is this idea for?", example="Defense Contractors, submarine manufacturers"),
|
53 |
+
IdeaStage(name="Existing Solutions", field="existing_solutions", question="What are some similar ideas or products that already exist today?", example="Nuclear Attack submarines and giant squids are somewhat similar to Shark with Laserbeams."),
|
54 |
+
IdeaStage(name="Unique Value", field="unique_value", question="How is your idea better or different?", example="Shark with Laserbeams are cheaper than Nuclear Attack submarines and the lasers are more powerful than squid tentacles."),
|
55 |
+
IdeaStage(name="Technical Challenges", field="technical_challenges", question="Are there any difficult technical problems with making this idea happen?", example="We would need to design a waterproof housing for the laser and batteries. We might need to experiment with how powerful lasers need to be when underwater in order to melt submarine steel hulls. We need to explore how to capture sharks and install the waterproof harnesses for the lasers."),
|
56 |
+
IdeaStage(name="Legal Barriers", field="legal_barriers", question="Any legal barriers?", example="We will need to obtain a weapons export license if we want to sell outside the United States."),
|
57 |
+
IdeaStage(name="Data Dependencies", field="data_dependencies", question="Any data dependencies?", example="We might need to get data on underwater motion vectors for creating the aiming mechanism for the lasers."),
|
58 |
+
IdeaStage(name="Team Roles", field="team_roles", question="What kind of people / job roles do you need to make this idea happen?", example="We will need marine biologists and fishermen for obtaining sharks. We will need electrical engineers, optical engineers and software engineers to create the laserbeam weapon. We will need project manager to help manage the budget and schedule. And we need a QA tester to ensure the laser is working underwater."),
|
59 |
+
IdeaStage(name="Timeline", field="timeline", question="About how long will it take to build the main components of your idea?", example="It will take a 2-3weeks to capture a shark. It will take 2-3 weeks to modify the harness and calibrate the laserbeam. I estimate it will take 3 months to train the shark to attack submarines."),
|
60 |
+
IdeaStage(name="Additional Info", field="additional_info", question="Anything else you'd want to add to help us understand and value your idea?", example="We might consider adding optional racing stripes or bioluminescent patterns ot the sharks as an upgrade with charge the customer for. We could explore a subscription model where we send the customers a new shark each quarter to replace sharks that age out of the program.")
|
61 |
+
]
|
main.py
ADDED
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from utils import SessionLocal, InnovativeIdea, ensure_database_exists, verify_database, initialize_database
|
3 |
+
from data_models import IdeaForm
|
4 |
+
from chatbot import InnovativeIdeaChatbot
|
5 |
+
from config import MODELS, DEFAULT_SYSTEM_PROMPT, STAGES
|
6 |
+
import logging
|
7 |
+
from typing import Dict, Any
|
8 |
+
|
9 |
+
# Set up logging
|
10 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
11 |
+
|
12 |
+
def create_gradio_interface():
|
13 |
+
innovative_chatbot = InnovativeIdeaChatbot()
|
14 |
+
default_stage = STAGES[0]["name"]
|
15 |
+
|
16 |
+
# Load initial data from the database
|
17 |
+
db = SessionLocal()
|
18 |
+
initial_idea = db.query(InnovativeIdea).first()
|
19 |
+
db.close()
|
20 |
+
|
21 |
+
if initial_idea is None:
|
22 |
+
logging.warning("No initial idea found in the database. Creating a new one.")
|
23 |
+
initial_idea = InnovativeIdea()
|
24 |
+
|
25 |
+
def chatbot_function(message, history, model, system_prompt, thinking_budget, current_stage):
|
26 |
+
try:
|
27 |
+
chat_history, form_data = innovative_chatbot.process_stage_input(current_stage, message, model, system_prompt, thinking_budget)
|
28 |
+
|
29 |
+
history.append((message, chat_history[-1][1]))
|
30 |
+
|
31 |
+
# Update the database with the new form data
|
32 |
+
db = SessionLocal()
|
33 |
+
idea = db.query(InnovativeIdea).first()
|
34 |
+
for key, value in form_data.items():
|
35 |
+
setattr(idea, key, value)
|
36 |
+
db.commit()
|
37 |
+
db.close()
|
38 |
+
|
39 |
+
return history, form_data.get(current_stage, ""), "" # Return an empty string to clear the input
|
40 |
+
except Exception as e:
|
41 |
+
logging.error(f"An error occurred in chatbot_function: {str(e)}", exc_info=True)
|
42 |
+
return history + [(None, f"An error occurred: {str(e)}")], "", "" # Return an empty string to clear the input
|
43 |
+
|
44 |
+
def fill_form(stage, model, thinking_budget):
|
45 |
+
form_data = innovative_chatbot.fill_out_form(stage, model, thinking_budget)
|
46 |
+
return form_data
|
47 |
+
|
48 |
+
def clear_chat():
|
49 |
+
# Reset the database to an empty form
|
50 |
+
db = SessionLocal()
|
51 |
+
idea = db.query(InnovativeIdea).first()
|
52 |
+
empty_form = IdeaForm()
|
53 |
+
for key, value in empty_form.dict().items():
|
54 |
+
setattr(idea, key, value)
|
55 |
+
db.commit()
|
56 |
+
db.close()
|
57 |
+
|
58 |
+
return innovative_chatbot.reset()
|
59 |
+
|
60 |
+
def update_form_field(stage_name: str, value: str) -> str:
|
61 |
+
db = SessionLocal()
|
62 |
+
idea = db.query(InnovativeIdea).first()
|
63 |
+
field_name = next(stage["field"] for stage in STAGES if stage["name"] == stage_name)
|
64 |
+
setattr(idea, field_name, value)
|
65 |
+
db.commit()
|
66 |
+
db.close()
|
67 |
+
return value
|
68 |
+
|
69 |
+
def update_placeholders(form_data: Dict[str, str]) -> Dict[str, Any]:
|
70 |
+
return {
|
71 |
+
stage["name"]: gr.update(value=form_data.get(stage["name"], ""), placeholder=form_data.get(stage["name"], stage["example"]))
|
72 |
+
for stage in STAGES
|
73 |
+
}
|
74 |
+
|
75 |
+
def start_over():
|
76 |
+
chat_history, form_data = innovative_chatbot.start_over()
|
77 |
+
return (
|
78 |
+
[], # Clear the chatbot
|
79 |
+
"", # Clear the message input
|
80 |
+
*[form_data.get(stage["field"], "") for stage in STAGES], # Reset all form fields
|
81 |
+
gr.update(value=default_stage) # Reset the stage selection
|
82 |
+
)
|
83 |
+
|
84 |
+
with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
85 |
+
gr.Markdown("# Innovative Idea Generator")
|
86 |
+
|
87 |
+
mode = gr.Radio(["Chatbot", "Direct Input"], label="Mode", value="Chatbot")
|
88 |
+
|
89 |
+
with gr.Row():
|
90 |
+
with gr.Column(scale=2):
|
91 |
+
chatbot = gr.Chatbot(label="Conversation", height=500)
|
92 |
+
msg = gr.Textbox(label="Your input", placeholder="Type your brilliant idea here...")
|
93 |
+
|
94 |
+
with gr.Row():
|
95 |
+
submit = gr.Button("Submit")
|
96 |
+
clear = gr.Button("Clear Chat")
|
97 |
+
start_over_btn = gr.Button("Start Over")
|
98 |
+
|
99 |
+
with gr.Column(scale=1):
|
100 |
+
stages = gr.Radio(
|
101 |
+
choices=[stage["name"] for stage in STAGES],
|
102 |
+
label="Ideation Stages",
|
103 |
+
value=default_stage
|
104 |
+
)
|
105 |
+
form_fields = {
|
106 |
+
stage["name"]: gr.Textbox(
|
107 |
+
label=stage["question"],
|
108 |
+
placeholder=stage["example"],
|
109 |
+
value=getattr(initial_idea, stage["field"], ""),
|
110 |
+
visible=(stage["name"] == default_stage),
|
111 |
+
interactive=False
|
112 |
+
) for stage in STAGES
|
113 |
+
}
|
114 |
+
fill_form_btn = gr.Button("Fill out Form")
|
115 |
+
submit_form_btn = gr.Button("Submit Form", visible=False)
|
116 |
+
|
117 |
+
with gr.Accordion("Advanced Settings", open=False):
|
118 |
+
model = gr.Dropdown(choices=MODELS, label="Select Model", value=MODELS[0])
|
119 |
+
system_prompt = gr.Textbox(label="System Prompt", value=DEFAULT_SYSTEM_PROMPT, lines=5)
|
120 |
+
thinking_budget = gr.Slider(minimum=1, maximum=4098, value=2048, step=1, label="Max New Tokens")
|
121 |
+
api_key = gr.Textbox(label="Hugging Face API Key", type="password")
|
122 |
+
|
123 |
+
# Event handlers
|
124 |
+
msg.submit(chatbot_function,
|
125 |
+
inputs=[msg, chatbot, model, system_prompt, thinking_budget, stages],
|
126 |
+
outputs=[chatbot, form_fields[default_stage], msg])
|
127 |
+
|
128 |
+
submit.click(chatbot_function,
|
129 |
+
inputs=[msg, chatbot, model, system_prompt, thinking_budget, stages],
|
130 |
+
outputs=[chatbot, form_fields[default_stage], msg])
|
131 |
+
|
132 |
+
def fill_and_update_form(stage, model, thinking_budget):
|
133 |
+
form_data = fill_form(stage, model, thinking_budget)
|
134 |
+
updated_fields = {}
|
135 |
+
for stage_name, value in form_data.items():
|
136 |
+
updated_value = update_form_field(stage_name, value)
|
137 |
+
updated_fields[stage_name] = updated_value
|
138 |
+
return update_placeholders(updated_fields)
|
139 |
+
|
140 |
+
fill_form_btn.click(fill_and_update_form,
|
141 |
+
inputs=[stages, model, thinking_budget],
|
142 |
+
outputs=list(form_fields.values()))
|
143 |
+
|
144 |
+
clear.click(clear_chat,
|
145 |
+
outputs=[chatbot] + list(form_fields.values()))
|
146 |
+
|
147 |
+
# Update form field visibility based on selected stage
|
148 |
+
stages.change(
|
149 |
+
lambda s: [gr.update(visible=(stage["name"] == s)) for stage in STAGES],
|
150 |
+
inputs=[stages],
|
151 |
+
outputs=list(form_fields.values())
|
152 |
+
)
|
153 |
+
|
154 |
+
# Update API key when changed
|
155 |
+
api_key.change(innovative_chatbot.set_api_key, inputs=[api_key])
|
156 |
+
|
157 |
+
# Toggle between chatbot and direct input mode
|
158 |
+
def toggle_mode(new_mode):
|
159 |
+
if new_mode == "Direct Input":
|
160 |
+
return [gr.update(visible=False)] * 3 + [gr.update(interactive=True)] * len(STAGES) + [gr.update(visible=True)]
|
161 |
+
else:
|
162 |
+
return [gr.update(visible=True)] * 3 + [gr.update(interactive=False)] * len(STAGES) + [gr.update(visible=False)]
|
163 |
+
|
164 |
+
mode.change(
|
165 |
+
toggle_mode,
|
166 |
+
inputs=[mode],
|
167 |
+
outputs=[chatbot, msg, submit] + list(form_fields.values()) + [submit_form_btn]
|
168 |
+
)
|
169 |
+
|
170 |
+
# Handle direct form submission
|
171 |
+
submit_form_btn.click(
|
172 |
+
lambda *values: values,
|
173 |
+
inputs=[form_fields[stage["name"]] for stage in STAGES],
|
174 |
+
outputs=[form_fields[stage["name"]] for stage in STAGES]
|
175 |
+
)
|
176 |
+
|
177 |
+
# Add this new event handler for the Start Over button
|
178 |
+
start_over_btn.click(
|
179 |
+
start_over,
|
180 |
+
outputs=[chatbot, msg] + [form_fields[stage["name"]] for stage in STAGES] + [stages]
|
181 |
+
)
|
182 |
+
|
183 |
+
return demo
|
184 |
+
|
185 |
+
def main():
|
186 |
+
ensure_database_exists()
|
187 |
+
initialize_database()
|
188 |
+
verify_database()
|
189 |
+
demo = create_gradio_interface()
|
190 |
+
return demo
|
191 |
+
|
192 |
+
if __name__ == "__main__":
|
193 |
+
demo = main()
|
194 |
+
demo.launch()
|
requirements.txt
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
pydantic
|
3 |
+
huggingface_hub
|
4 |
+
duckduckgo_search
|
5 |
+
python-dotenv
|
6 |
+
sqlalchemy
|
utils.py
ADDED
@@ -0,0 +1,456 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
from typing import Dict, List, Optional, Any
|
3 |
+
from pydantic import ValidationError
|
4 |
+
from data_models import IdeaForm, IDEA_STAGES, InnovativeIdea, Base
|
5 |
+
from config import API_TOKEN, STAGES
|
6 |
+
from huggingface_hub import InferenceClient
|
7 |
+
from duckduckgo_search import DDGS
|
8 |
+
from sqlalchemy import create_engine, delete, inspect
|
9 |
+
from sqlalchemy.orm import sessionmaker, Session, declarative_base
|
10 |
+
import sys
|
11 |
+
import sqlite3
|
12 |
+
from sqlalchemy.exc import OperationalError, PendingRollbackError
|
13 |
+
import logging
|
14 |
+
import os
|
15 |
+
|
16 |
+
# Database configuration
|
17 |
+
DATABASE_URL = "sqlite:///./innovative_ideas.db"
|
18 |
+
engine = create_engine(DATABASE_URL)
|
19 |
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
20 |
+
Base = declarative_base()
|
21 |
+
|
22 |
+
def get_llm_response(context: str, model: str, max_tokens: int, api_key: Optional[str] = None) -> str:
|
23 |
+
client = InferenceClient(model=model, token=api_key or API_TOKEN)
|
24 |
+
|
25 |
+
messages = [
|
26 |
+
{"role": "system", "content": "You are a helpful AI assistant."},
|
27 |
+
{"role": "user", "content": context}
|
28 |
+
]
|
29 |
+
|
30 |
+
full_response = ""
|
31 |
+
for message in client.chat_completion(
|
32 |
+
messages=messages,
|
33 |
+
max_tokens=max_tokens,
|
34 |
+
temperature=0.7,
|
35 |
+
top_p=0.95,
|
36 |
+
stream=True,
|
37 |
+
):
|
38 |
+
content = message.choices[0].delta.content
|
39 |
+
if content:
|
40 |
+
full_response += content
|
41 |
+
print(content, end="", flush=True)
|
42 |
+
|
43 |
+
print() # New line after the full response
|
44 |
+
return full_response
|
45 |
+
|
46 |
+
def extract_form_data(llm_response: str) -> Dict[str, Any]:
|
47 |
+
form_data = {}
|
48 |
+
|
49 |
+
# Define patterns for each field
|
50 |
+
patterns = {stage["field"]: rf'{stage["name"]}:?\s*(.*?)(?:\n\n|\Z)' for stage in STAGES}
|
51 |
+
|
52 |
+
# Extract data for each field
|
53 |
+
for field, pattern in patterns.items():
|
54 |
+
match = re.search(pattern, llm_response, re.DOTALL | re.IGNORECASE)
|
55 |
+
if match:
|
56 |
+
form_data[field] = match.group(1).strip()
|
57 |
+
|
58 |
+
# Special handling for team_roles (convert to list)
|
59 |
+
if 'team_roles' in form_data:
|
60 |
+
form_data['team_roles'] = [role.strip() for role in form_data['team_roles'].split(',')]
|
61 |
+
|
62 |
+
return form_data
|
63 |
+
|
64 |
+
def perform_web_search(query: str, max_results: int = 3) -> str:
|
65 |
+
with DDGS() as ddgs:
|
66 |
+
results = list(ddgs.text(query, max_results=max_results))
|
67 |
+
|
68 |
+
formatted_results = ""
|
69 |
+
for i, result in enumerate(results, 1):
|
70 |
+
formatted_results += f"{i}. {result['title']}\n {result['body']}\n URL: {result['href']}\n\n"
|
71 |
+
|
72 |
+
return formatted_results
|
73 |
+
|
74 |
+
def optimize_search_query(query: str, model: str) -> str:
|
75 |
+
client = InferenceClient(model=model, token=API_TOKEN)
|
76 |
+
prompt = f"Optimize the following search query to get better web search results:\n\n{query}\n\nOptimized query:"
|
77 |
+
|
78 |
+
response = client.text_generation(prompt, max_new_tokens=50, temperature=0.7)
|
79 |
+
return response.strip()
|
80 |
+
|
81 |
+
def refine_user_input(user_input: str, current_stage: str, model: str) -> str:
|
82 |
+
client = InferenceClient(model=model, token=API_TOKEN)
|
83 |
+
prompt = f"""
|
84 |
+
Refine and clarify the following user input for the '{current_stage}' stage of an innovative idea:
|
85 |
+
|
86 |
+
{user_input}
|
87 |
+
|
88 |
+
Please provide a clear, concise, and well-structured version of this input.
|
89 |
+
Ensure that the refined input is specific to the current stage and does not include information for other stages.
|
90 |
+
"""
|
91 |
+
messages = [
|
92 |
+
{"role": "system", "content": "You are a helpful AI assistant specializing in refining innovative ideas."},
|
93 |
+
{"role": "user", "content": prompt}
|
94 |
+
]
|
95 |
+
|
96 |
+
full_response = ""
|
97 |
+
for message in client.chat_completion(
|
98 |
+
messages=messages,
|
99 |
+
max_tokens=200,
|
100 |
+
temperature=0.7,
|
101 |
+
stream=True,
|
102 |
+
):
|
103 |
+
content = message.choices[0].delta.content
|
104 |
+
if content:
|
105 |
+
full_response += content
|
106 |
+
|
107 |
+
return full_response.strip()
|
108 |
+
|
109 |
+
def update_idea_form(form: IdeaForm, new_data: Dict) -> Optional[IdeaForm]:
|
110 |
+
"""
|
111 |
+
Updates the IdeaForm with new data and validates it.
|
112 |
+
"""
|
113 |
+
try:
|
114 |
+
updated_data = form.dict()
|
115 |
+
updated_data.update(new_data)
|
116 |
+
return IdeaForm(**updated_data)
|
117 |
+
except ValidationError as e:
|
118 |
+
print(f"Validation error: {e}")
|
119 |
+
return None
|
120 |
+
|
121 |
+
def update_checklist(idea_form: IdeaForm) -> str:
|
122 |
+
"""
|
123 |
+
Generates a checklist based on the current state of the idea form.
|
124 |
+
"""
|
125 |
+
checklist = []
|
126 |
+
for field, value in idea_form.dict().items():
|
127 |
+
if not value:
|
128 |
+
checklist.append(f"[ ] Complete the '{field.replace('_', ' ').title()}' section")
|
129 |
+
elif isinstance(value, str) and len(value) < 50:
|
130 |
+
checklist.append(f"[?] Consider expanding the '{field.replace('_', ' ').title()}' section")
|
131 |
+
else:
|
132 |
+
checklist.append(f"[x] '{field.replace('_', ' ').title()}' section completed")
|
133 |
+
|
134 |
+
return "\n".join(checklist)
|
135 |
+
|
136 |
+
def generate_follow_up_questions(idea_form: IdeaForm, current_stage: int) -> List[str]:
|
137 |
+
"""
|
138 |
+
Generates follow-up questions based on the current stage and form state.
|
139 |
+
"""
|
140 |
+
questions = []
|
141 |
+
current_stage_name = IDEA_STAGES[current_stage]
|
142 |
+
form_dict = idea_form.dict()
|
143 |
+
|
144 |
+
if current_stage_name == "Idea Name":
|
145 |
+
if not form_dict['idea_name']:
|
146 |
+
questions.append("What would be a catchy and memorable name for your idea?")
|
147 |
+
elif len(form_dict['idea_name']) > 50:
|
148 |
+
questions.append("Can you shorten your idea name to make it more concise?")
|
149 |
+
|
150 |
+
elif current_stage_name == "Idea Overview":
|
151 |
+
if not form_dict['idea_overview']:
|
152 |
+
questions.append("Can you provide a brief overview of your idea in simple terms?")
|
153 |
+
elif len(form_dict['idea_overview']) < 100:
|
154 |
+
questions.append("Can you elaborate more on how your idea works?")
|
155 |
+
|
156 |
+
elif current_stage_name == "Problem Solution":
|
157 |
+
if not form_dict['problem_solution']:
|
158 |
+
questions.append("What specific problem does your idea solve?")
|
159 |
+
if 'how' not in form_dict['problem_solution'].lower():
|
160 |
+
questions.append("How exactly does your idea solve the problem you've identified?")
|
161 |
+
|
162 |
+
elif current_stage_name == "Target Customers":
|
163 |
+
if not form_dict['target_customers']:
|
164 |
+
questions.append("Who are the main users or customers for your idea?")
|
165 |
+
elif len(form_dict['target_customers']) < 50:
|
166 |
+
questions.append("Can you be more specific about your target customers? Consider demographics, industries, or use cases.")
|
167 |
+
|
168 |
+
elif current_stage_name == "Market Value":
|
169 |
+
if not form_dict['market_value']:
|
170 |
+
questions.append("What industries or markets could benefit from your idea?")
|
171 |
+
if 'size' not in form_dict['market_value'].lower():
|
172 |
+
questions.append("Can you estimate the size of the market for your idea?")
|
173 |
+
|
174 |
+
elif current_stage_name == "Existing Solutions":
|
175 |
+
if not form_dict['existing_solutions']:
|
176 |
+
questions.append("Are there any existing products or services similar to your idea?")
|
177 |
+
elif 'different' not in form_dict['existing_solutions'].lower():
|
178 |
+
questions.append("How is your idea different from these existing solutions?")
|
179 |
+
|
180 |
+
elif current_stage_name == "Unique Value":
|
181 |
+
if not form_dict['unique_value']:
|
182 |
+
questions.append("What makes your idea unique or better than existing solutions?")
|
183 |
+
if 'why' not in form_dict['unique_value'].lower():
|
184 |
+
questions.append("Why would customers choose your solution over alternatives?")
|
185 |
+
|
186 |
+
elif current_stage_name == "Technical Challenges":
|
187 |
+
if not form_dict['technical_challenges']:
|
188 |
+
questions.append("What are the main technical challenges in developing your idea?")
|
189 |
+
if 'overcome' not in form_dict['technical_challenges'].lower():
|
190 |
+
questions.append("How might these technical challenges be overcome?")
|
191 |
+
|
192 |
+
elif current_stage_name == "Legal Barriers":
|
193 |
+
if not form_dict['legal_barriers']:
|
194 |
+
questions.append("Are there any legal or regulatory issues that could affect your idea?")
|
195 |
+
if 'address' not in form_dict['legal_barriers'].lower():
|
196 |
+
questions.append("How might you address these legal or regulatory issues?")
|
197 |
+
|
198 |
+
elif current_stage_name == "Data Dependencies":
|
199 |
+
if not form_dict['data_dependencies']:
|
200 |
+
questions.append("Does your idea rely on any specific data sources?")
|
201 |
+
if 'acquire' not in form_dict['data_dependencies'].lower():
|
202 |
+
questions.append("How will you acquire or generate the necessary data for your idea?")
|
203 |
+
|
204 |
+
elif current_stage_name == "Team Roles":
|
205 |
+
if not form_dict['team_roles']:
|
206 |
+
questions.append("What key roles or expertise are needed to develop and implement your idea?")
|
207 |
+
elif len(form_dict['team_roles']) < 3:
|
208 |
+
questions.append("Are there any additional roles or skills that would be beneficial for your team?")
|
209 |
+
|
210 |
+
elif current_stage_name == "Timeline":
|
211 |
+
if not form_dict['timeline']:
|
212 |
+
questions.append("Can you provide a rough timeline for developing your idea?")
|
213 |
+
if 'milestone' not in form_dict['timeline'].lower():
|
214 |
+
questions.append("What are the main milestones in your development timeline?")
|
215 |
+
|
216 |
+
elif current_stage_name == "Additional Info":
|
217 |
+
if not form_dict['additional_info']:
|
218 |
+
questions.append("Is there any additional information that's important for understanding or implementing your idea?")
|
219 |
+
elif len(form_dict['additional_info']) < 100:
|
220 |
+
questions.append("Are there any other aspects of your idea that you'd like to elaborate on?")
|
221 |
+
|
222 |
+
return questions
|
223 |
+
|
224 |
+
def save_idea_to_database(form: IdeaForm, db: Session) -> int:
|
225 |
+
"""
|
226 |
+
Saves the IdeaForm to the SQLite database.
|
227 |
+
Returns the ID of the inserted row.
|
228 |
+
"""
|
229 |
+
db_idea = InnovativeIdea(
|
230 |
+
idea_name=form.idea_name,
|
231 |
+
idea_overview=form.idea_overview,
|
232 |
+
problem_solution=form.problem_solution,
|
233 |
+
target_customers=form.target_customers,
|
234 |
+
market_value=form.market_value,
|
235 |
+
existing_solutions=form.existing_solutions,
|
236 |
+
unique_value=form.unique_value,
|
237 |
+
technical_challenges=form.technical_challenges,
|
238 |
+
legal_barriers=form.legal_barriers,
|
239 |
+
data_dependencies=form.data_dependencies,
|
240 |
+
team_roles=','.join(form.team_roles) if form.team_roles else None,
|
241 |
+
timeline=form.timeline,
|
242 |
+
additional_info=form.additional_info
|
243 |
+
)
|
244 |
+
db.add(db_idea)
|
245 |
+
db.commit()
|
246 |
+
db.refresh(db_idea)
|
247 |
+
return db_idea.id
|
248 |
+
|
249 |
+
def load_idea_from_database(idea_id: int, db: Session) -> Optional[IdeaForm]:
|
250 |
+
"""
|
251 |
+
Loads an IdeaForm from the SQLite database by ID.
|
252 |
+
"""
|
253 |
+
db_idea = db.query(InnovativeIdea).filter(InnovativeIdea.id == idea_id).first()
|
254 |
+
if db_idea:
|
255 |
+
return IdeaForm(
|
256 |
+
idea_name=db_idea.idea_name,
|
257 |
+
idea_overview=db_idea.idea_overview,
|
258 |
+
problem_solution=db_idea.problem_solution,
|
259 |
+
target_customers=db_idea.target_customers,
|
260 |
+
market_value=db_idea.market_value,
|
261 |
+
existing_solutions=db_idea.existing_solutions,
|
262 |
+
unique_value=db_idea.unique_value,
|
263 |
+
technical_challenges=db_idea.technical_challenges,
|
264 |
+
legal_barriers=db_idea.legal_barriers,
|
265 |
+
data_dependencies=db_idea.data_dependencies,
|
266 |
+
team_roles=db_idea.team_roles.split(',') if db_idea.team_roles else None,
|
267 |
+
timeline=db_idea.timeline,
|
268 |
+
additional_info=db_idea.additional_info
|
269 |
+
)
|
270 |
+
return None
|
271 |
+
|
272 |
+
def update_idea_in_database(idea_id: int, form: IdeaForm, db: Session) -> bool:
|
273 |
+
"""
|
274 |
+
Updates an existing idea in the database.
|
275 |
+
"""
|
276 |
+
db_idea = db.query(InnovativeIdea).filter(InnovativeIdea.id == idea_id).first()
|
277 |
+
if db_idea:
|
278 |
+
for field, value in form.dict(exclude_unset=True).items():
|
279 |
+
setattr(db_idea, field, value)
|
280 |
+
db.commit()
|
281 |
+
return True
|
282 |
+
return False
|
283 |
+
|
284 |
+
def extract_search_query(message: str) -> Optional[str]:
|
285 |
+
"""
|
286 |
+
Extract a search query from a user message if it starts with '@'.
|
287 |
+
"""
|
288 |
+
if message.startswith('@'):
|
289 |
+
return message[1:].strip()
|
290 |
+
return None
|
291 |
+
|
292 |
+
def create_tables():
|
293 |
+
Base.metadata.create_all(bind=engine)
|
294 |
+
|
295 |
+
def get_db():
|
296 |
+
db = SessionLocal()
|
297 |
+
try:
|
298 |
+
yield db
|
299 |
+
finally:
|
300 |
+
db.close()
|
301 |
+
|
302 |
+
def verify_database():
|
303 |
+
try:
|
304 |
+
inspector = inspect(engine)
|
305 |
+
if not inspector.has_table("innovative_ideas"):
|
306 |
+
logging.error("InnovativeIdea table does not exist")
|
307 |
+
return False
|
308 |
+
|
309 |
+
columns = inspector.get_columns("innovative_ideas")
|
310 |
+
expected_columns = [field for field in IdeaForm.__fields__]
|
311 |
+
actual_columns = [column['name'] for column in columns if column['name'] != 'id']
|
312 |
+
|
313 |
+
if set(expected_columns) != set(actual_columns):
|
314 |
+
logging.error(f"Mismatch in table columns. Expected: {expected_columns}, Actual: {actual_columns}")
|
315 |
+
return False
|
316 |
+
|
317 |
+
# Check if there's at least one row in the table
|
318 |
+
db = SessionLocal()
|
319 |
+
idea_count = db.query(InnovativeIdea).count()
|
320 |
+
db.close()
|
321 |
+
|
322 |
+
if idea_count == 0:
|
323 |
+
logging.warning("No ideas found in the database")
|
324 |
+
# Instead of returning False, we'll create an initial idea
|
325 |
+
db = SessionLocal()
|
326 |
+
initial_idea = InnovativeIdea()
|
327 |
+
db.add(initial_idea)
|
328 |
+
db.commit()
|
329 |
+
db.close()
|
330 |
+
logging.info("Created initial idea in the database")
|
331 |
+
|
332 |
+
return True
|
333 |
+
except Exception as e:
|
334 |
+
logging.error(f"Database verification failed: {str(e)}", exc_info=True)
|
335 |
+
return False
|
336 |
+
|
337 |
+
def initialize_database():
|
338 |
+
try:
|
339 |
+
# Create tables
|
340 |
+
Base.metadata.create_all(bind=engine)
|
341 |
+
logging.info("Database tables created successfully.")
|
342 |
+
|
343 |
+
# Check if the table is empty
|
344 |
+
db = SessionLocal()
|
345 |
+
existing_idea = db.query(InnovativeIdea).first()
|
346 |
+
|
347 |
+
if existing_idea is None:
|
348 |
+
# Create an empty IdeaForm
|
349 |
+
empty_form = IdeaForm()
|
350 |
+
|
351 |
+
# Save the empty form to the database
|
352 |
+
db_idea = InnovativeIdea(**empty_form.dict())
|
353 |
+
db.add(db_idea)
|
354 |
+
db.commit()
|
355 |
+
db.refresh(db_idea)
|
356 |
+
logging.info("Empty idea form added to the database.")
|
357 |
+
else:
|
358 |
+
logging.info("Database already contains data.")
|
359 |
+
|
360 |
+
db.close()
|
361 |
+
return True
|
362 |
+
except Exception as e:
|
363 |
+
logging.error(f"Failed to initialize database: {str(e)}")
|
364 |
+
return False
|
365 |
+
|
366 |
+
def init_db():
|
367 |
+
Base.metadata.create_all(bind=engine)
|
368 |
+
|
369 |
+
def get_example_idea() -> Dict[str, str]:
|
370 |
+
"""
|
371 |
+
Returns an example idea to guide users and the LLM.
|
372 |
+
"""
|
373 |
+
return {
|
374 |
+
"idea_name": "Sharks with Laserbeams",
|
375 |
+
"idea_overview": "My idea is to attach laserbeams to sharks to create the ultimate evil weapon. The laserbeams are powered by a battery that are recharged by the shark's swimming motion. The laserbeams are used to attack enemy submarines.",
|
376 |
+
"problem_solution": "Our customers' secret lairs are often attacked by submarines. If our clients had sharks with laserbeams they could attack and destroy the submarines, saving the secret lair from being discovered.",
|
377 |
+
"target_customers": "Evil geniuses, tyrannical dictators, rogue government agencies",
|
378 |
+
"market_value": "Defense Contractors, submarine manufacturers",
|
379 |
+
"existing_solutions": "Nuclear Attack submarines and giant squids are somewhat similar to Shark with Laserbeams.",
|
380 |
+
"unique_value": "Shark with Laserbeams are cheaper than Nuclear Attack submarines and the lasers are more powerful than squid tentacles.",
|
381 |
+
"technical_challenges": "We would need to design a waterproof housing for the laser and batteries. We might need to experiment with how powerful lasers need to be when underwater in order to melt submarine steel hulls. We need to explore how to capture sharks and install the waterproof harnesses for the lasers.",
|
382 |
+
"legal_barriers": "We will need to obtain a weapons export license if we want to sell outside the United States.",
|
383 |
+
"data_dependencies": "We might need to get data on underwater motion vectors for creating the aiming mechanism for the lasers.",
|
384 |
+
"team_roles": "Marine biologists, fishermen, electrical engineers, optical engineers, software engineers, project manager, QA tester",
|
385 |
+
"timeline": "It will take 2-3 weeks to capture a shark. It will take 2-3 weeks to modify the harness and calibrate the laserbeam. I estimate it will take 3 months to train the shark to attack submarines.",
|
386 |
+
"additional_info": "We might consider adding optional racing stripes or bioluminescent patterns to the sharks as an upgrade with charge the customer for. We could explore a subscription model where we send the customers a new shark each quarter to replace sharks that age out of the program."
|
387 |
+
}
|
388 |
+
|
389 |
+
def generate_prompt_for_stage(stage: str, current_form: Dict[str, Any]) -> str:
|
390 |
+
"""
|
391 |
+
Generates a prompt for the current stage, including the example idea.
|
392 |
+
"""
|
393 |
+
example_idea = get_example_idea()
|
394 |
+
prompt = f"We are currently in the '{stage}' stage of developing an innovative idea. "
|
395 |
+
prompt += "Please provide information for this stage, keeping in mind the following example:\n\n"
|
396 |
+
|
397 |
+
if stage == "Idea Name":
|
398 |
+
prompt += f"Example: {example_idea['idea_name']}\n"
|
399 |
+
prompt += "What's the name of your innovative idea? Keep it short and catchy."
|
400 |
+
elif stage == "Idea Overview":
|
401 |
+
prompt += f"Example: {example_idea['idea_overview']}\n"
|
402 |
+
prompt += "Provide a simple overview of your idea, as if explaining it to a 10-year-old child. What does your idea do?"
|
403 |
+
elif stage == "Problem Solution":
|
404 |
+
prompt += f"Example: {example_idea['problem_solution']}\n"
|
405 |
+
prompt += "What specific problem does your idea solve? How does it solve this problem?"
|
406 |
+
elif stage == "Target Customers":
|
407 |
+
prompt += f"Example: {example_idea['target_customers']}\n"
|
408 |
+
prompt += "Who are the main customers or users for your idea? Be as specific as possible."
|
409 |
+
elif stage == "Market Value":
|
410 |
+
prompt += f"Example: {example_idea['market_value']}\n"
|
411 |
+
prompt += "What industries or markets could benefit from your idea? How large is this market?"
|
412 |
+
elif stage == "Existing Solutions":
|
413 |
+
prompt += f"Example: {example_idea['existing_solutions']}\n"
|
414 |
+
prompt += "Are there any existing products or services similar to your idea? How are they different?"
|
415 |
+
elif stage == "Unique Value":
|
416 |
+
prompt += f"Example: {example_idea['unique_value']}\n"
|
417 |
+
prompt += "What makes your idea unique or better than existing solutions? Why would customers choose your solution?"
|
418 |
+
elif stage == "Technical Challenges":
|
419 |
+
prompt += f"Example: {example_idea['technical_challenges']}\n"
|
420 |
+
prompt += "What are the main technical challenges in developing your idea? How might these be overcome?"
|
421 |
+
elif stage == "Legal Barriers":
|
422 |
+
prompt += f"Example: {example_idea['legal_barriers']}\n"
|
423 |
+
prompt += "Are there any legal or regulatory issues that could affect your idea? How might these be addressed?"
|
424 |
+
elif stage == "Data Dependencies":
|
425 |
+
prompt += f"Example: {example_idea['data_dependencies']}\n"
|
426 |
+
prompt += "Does your idea rely on any specific data sources? How will you acquire or generate this data?"
|
427 |
+
elif stage == "Team Roles":
|
428 |
+
prompt += f"Example: {example_idea['team_roles']}\n"
|
429 |
+
prompt += "What key roles or expertise are needed to develop and implement your idea? List specific job titles or skills."
|
430 |
+
elif stage == "Timeline":
|
431 |
+
prompt += f"Example: {example_idea['timeline']}\n"
|
432 |
+
prompt += "Provide a rough timeline for developing your idea. What are the main milestones and how long might each take?"
|
433 |
+
elif stage == "Additional Info":
|
434 |
+
prompt += f"Example: {example_idea['additional_info']}\n"
|
435 |
+
prompt += "Is there any additional information that's important for understanding or implementing your idea?"
|
436 |
+
|
437 |
+
prompt += "\n\nPlease provide your response for this stage, considering the example provided and the current state of your idea."
|
438 |
+
return prompt
|
439 |
+
|
440 |
+
def ensure_database_exists():
|
441 |
+
db_path = DATABASE_URL.replace("sqlite:///", "")
|
442 |
+
if not os.path.exists(db_path):
|
443 |
+
logging.info(f"Database file not found. Creating new database at {db_path}")
|
444 |
+
open(db_path, 'a').close() # Create an empty file
|
445 |
+
else:
|
446 |
+
logging.info(f"Database file found at {db_path}")
|
447 |
+
|
448 |
+
def clear_database(db: Session):
|
449 |
+
try:
|
450 |
+
# Delete all records from the InnovativeIdea table
|
451 |
+
db.query(InnovativeIdea).delete()
|
452 |
+
db.commit()
|
453 |
+
logging.info("Database cleared successfully.")
|
454 |
+
except Exception as e:
|
455 |
+
db.rollback()
|
456 |
+
logging.error(f"Error clearing database: {str(e)}")
|