← all conversations

Simplified API Rewrite

2024-11-214 turns27,650 charso1-preview
simplified-apitext-based-interfacelocal-ollama-model

Summary

user wants a simplified api program that uses text entries and local ollama model

Messages

This application does not work, can you rewrite it as a simpler program that does work: # api.py from persona_interface import PersonaInterface from fastapi import FastAPI, File, UploadFile from pydantic import BaseModel from typing import Optional import uvicorn app = FastAPI() # Store persona instance globally (in production, you'd want proper session management) persona_interface = None class ChatRequest(BaseModel): message: str adjust_emotional_variability: Optional[float] = None @app.post("/initialize") async def initialize_persona(audio_file: UploadFile = File(...)): global persona_interface # Save uploaded file temporarily file_location = f"temp_{audio_file.filename}" with open(file_location, "wb+") as file_object: file_object.write(await audio_file.read()) try: persona_interface = PersonaInterface() persona_interface.initialize_from_audio(file_location) # Clean up temporary file import os os.remove(file_location) return {"status": "success", "message": "Persona initialized successfully"} except Exception as e: return {"status": "error", "message": str(e)} @app.post("/chat") async def chat(request: ChatRequest): global persona_interface if not persona_interface: return {"status": "error", "message": "Persona not initialized"} try: # Adjust emotional variability if specified if request.adjust_emotional_variability is not None: persona_interface.adjust_emotional_variability(request.adjust_emotional_variability) # Generate response response = persona_interface.chat(request.message) # Get current metrics metrics = persona_interface.get_persona_metrics() return { "status": "success", "response": response, "emotional_state": metrics['emotional_state'], "personality_metrics": metrics['personality'] } except Exception as e: return {"status": "error", "message": str(e)} @app.get("/metrics") async def get_metrics(): global persona_interface if not persona_interface: return {"status": "error", "message": "Persona not initialized"} return { "status": "success", "metrics": persona_interface.get_persona_metrics() } @app.post("/save") async def save_persona(filename: str): global persona_interface if not persona_interface: return {"status": "error", "message": "Persona not initialized"} try: persona_interface.save_persona(f"{filename}.json") return {"status": "success", "message": "Persona saved successfully"} except Exception as e: return {"status": "error", "message": str(e)} @app.post("/load") async def load_persona(filename: str): global persona_interface try: persona_interface = PersonaInterface() persona_interface.load_persona(f"{filename}.json") return {"status": "success", "message": "Persona loaded successfully"} except Exception as e: return {"status": "error", "message": str(e)} if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000) # emotional_core.py import numpy as np from textblob import TextBlob from typing import Dict, List, Tuple class EmotionalCore: def __init__(self, base_emotional_state: Dict[str, float] = None): self.base_emotional_state = base_emotional_state or { 'valence': 0.0, # positive/negative (-1 to 1) 'arousal': 0.0, # energy level (0 to 1) 'dominance': 0.5 # confidence level (0 to 1) } self.emotional_history = [] self.chaos_factor = 0.2 # adjustable chaos/stability parameter def analyze_emotion(self, text: str) -> Dict[str, float]: """Analyze emotional content of text using TextBlob""" analysis = TextBlob(text) # Extract sentiment metrics sentiment = analysis.sentiment return { 'valence': sentiment.polarity, 'arousal': abs(sentiment.polarity) * sentiment.subjectivity, 'dominance': sentiment.subjectivity } def apply_emotional_dynamics(self) -> Dict[str, float]: """Apply chaotic dynamics to emotional state""" current_state = self.base_emotional_state.copy() # Add controlled randomness for dimension in current_state: noise = np.random.normal(0, self.chaos_factor) current_state[dimension] = np.clip( current_state[dimension] + noise, -1.0, 1.0 ) self.emotional_history.append(current_state) return current_state # emotional_memory.py from collections import deque from typing import Dict, List import numpy as np class EmotionalMemory: def __init__(self, memory_size: int = 10): self.memory_size = memory_size self.interaction_history = deque(maxlen=memory_size) self.emotional_trends = { 'valence': deque(maxlen=memory_size), 'arousal': deque(maxlen=memory_size), 'dominance': deque(maxlen=memory_size) } def add_interaction(self, prompt: str, response: str, emotional_state: Dict[str, float]): """Store interaction and emotional state""" self.interaction_history.append({ 'prompt': prompt, 'response': response, 'emotional_state': emotional_state }) for dimension, value in emotional_state.items(): if dimension in self.emotional_trends: self.emotional_trends[dimension].append(value) def get_emotional_context(self) -> Dict[str, float]: """Calculate emotional context based on recent history""" if not self.interaction_history: return None context = {} for dimension in self.emotional_trends: if self.emotional_trends[dimension]: # Calculate weighted average, giving more weight to recent interactions weights = np.exp(np.linspace(-1, 0, len(self.emotional_trends[dimension]))) values = np.array(list(self.emotional_trends[dimension])) context[dimension] = np.average(values, weights=weights) return context def get_relevant_memories(self, prompt: str, k: int = 3) -> List[Dict]: """Retrieve relevant past interactions based on prompt similarity""" if not self.interaction_history: return [] # Simple keyword-based relevance (could be improved with embedding similarity) prompt_words = set(prompt.lower().split()) relevant = [] for interaction in reversed(self.interaction_history): interaction_words = set(interaction['prompt'].lower().split()) similarity = len(prompt_words.intersection(interaction_words)) / len(prompt_words) if similarity > 0.2: # threshold for relevance relevant.append(interaction) if len(relevant) >= k: break return relevant # example_usage.py def main(): # Initialize the persona interface persona = PersonaInterface() # Load from an audio interview try: persona.initialize_from_audio("interview.wav") except Exception as e: print(f"Error loading audio: {e}") return # Example conversation loop print("Persona initialized. Start chatting! (type 'quit' to exit)") while True: user_input = input("You: ").strip() if user_input.lower() == 'quit': break try: response = persona.chat(user_input) print(f"Persona: {response}") # Optional: print current emotional state metrics = persona.get_persona_metrics() print(f"\nCurrent emotional state: {metrics['emotional_state']}") except Exception as e: print(f"Error generating response: {e}") # Save persona state persona.save_persona("persona_state.json") if __name__ == "__main__": main() # persona_generator.py from typing import List, Dict import whisper from emotional_core import EmotionalCore class PersonaGenerator: def __init__(self): self.emotional_core = EmotionalCore() self.persona_metrics = {} self.transcriber = whisper.load_model("base") # Initialize Whisper model def transcribe_interview(self, audio_path: str) -> str: """Transcribe audio interview to text""" result = self.transcriber.transcribe(audio_path) return result["text"] def parse_qa_pairs(self, transcript: str) -> List[Dict[str, str]]: """Parse transcript into question-answer pairs""" # This is a simplified version - you'd need more sophisticated parsing qa_pairs = [] segments = transcript.split("\n") for i in range(0, len(segments), 2): if i + 1 < len(segments): qa_pairs.append({ 'question': segments[i], 'answer': segments[i + 1] }) return qa_pairs # Return the list def analyze_qa_pairs(self, qa_pairs: List[Dict[str, str]]) -> Dict: """Analyze Q&A pairs for emotional patterns and personality metrics""" emotional_patterns = [] personality_metrics = { 'openness': 0.0, 'conscientiousness': 0.0, 'extraversion': 0.0, 'agreeableness': 0.0, 'neuroticism': 0.0 } for qa in qa_pairs: # Analyze answer emotions emotion = self.emotional_core.analyze_emotion(qa['answer']) emotional_patterns.append(emotion) # Update personality metrics based on answer content # This is a simplified example - you'd want more sophisticated analysis personality_metrics['openness'] += emotion['valence'] * 0.2 personality_metrics['extraversion'] += emotion['arousal'] * 0.3 personality_metrics['neuroticism'] += (1 - emotion['dominance']) * 0.25 # Normalize personality metrics for metric in personality_metrics: personality_metrics[metric] = np.clip(personality_metrics[metric], 0, 1) return { 'emotional_patterns': emotional_patterns, 'personality_metrics': personality_metrics } def generate_persona(self, audio_path: str) -> Dict: """Generate complete persona from audio interview""" # Transcribe interview transcript = self.transcribe_interview(audio_path) # Parse into Q&A pairs qa_pairs = self.parse_qa_pairs(transcript) # Analyze patterns analysis = self.analyze_qa_pairs(qa_pairs) # Create persona profile persona = { 'qa_database': qa_pairs, 'emotional_baseline': analysis['emotional_patterns'], 'personality_metrics': analysis['personality_metrics'], 'response_style': self.extract_response_style(qa_pairs) } self.persona_metrics = persona return persona def extract_response_style(self, qa_pairs: List[Dict[str, str]]) -> Dict: """Extract linguistic style patterns from responses""" style_metrics = { 'avg_response_length': 0, 'vocabulary_diversity': 0, 'formality_level': 0 } all_words = [] for qa in qa_pairs: words = qa['answer'].split() all_words.extend(words) style_metrics['avg_response_length'] += len(words) style_metrics['avg_response_length'] /= len(qa_pairs) style_metrics['vocabulary_diversity'] = len(set(all_words)) / len(all_words) return style_metrics # persona_interface.py from response_generator import ResponseGenerator from persona_generator import PersonaGenerator from typing import Dict class PersonaInterface: def __init__(self, audio_path: str = None): self.persona_generator = PersonaGenerator() self.emotional_memory = EmotionalMemory() self.response_generator = None if audio_path: self.initialize_from_audio(audio_path) def initialize_from_audio(self, audio_path: str): """Initialize persona from audio interview""" persona_metrics = self.persona_generator.generate_persona(audio_path) self.response_generator = ResponseGenerator(persona_metrics) def chat(self, prompt: str) -> str: """Generate a response to user input""" if not self.response_generator: raise ValueError("Persona not initialized. Please provide an audio interview first.") # Get emotional context emotional_context = self.emotional_memory.get_emotional_context() # Generate response response = self.response_generator.generate_response(prompt, emotional_context) # Store interaction current_emotional_state = self.response_generator.emotional_core.base_emotional_state self.emotional_memory.add_interaction(prompt, response, current_emotional_state) return response def get_persona_metrics(self) -> Dict: """Get current persona metrics and state""" if not self.response_generator: return None return { 'personality': self.persona_generator.persona_metrics['personality_metrics'], 'emotional_state': self.response_generator.emotional_core.base_emotional_state, 'response_style': self.persona_generator.persona_metrics['response_style'], 'interaction_history': len(self.emotional_memory.interaction_history) } def adjust_emotional_variability(self, chaos_factor: float): """Adjust how variable the emotional responses are""" if not 0 <= chaos_factor <= 1: raise ValueError("Chaos factor must be between 0 and 1") self.response_generator.emotional_core.chaos_factor = chaos_factor def save_persona(self, filepath: str): """Save persona state to file""" import json state = { 'persona_metrics': self.persona_generator.persona_metrics, 'emotional_state': self.response_generator.emotional_core.base_emotional_state, 'emotional_history': list(self.emotional_memory.interaction_history) } with open(filepath, 'w') as f: json.dump(state, f) def load_persona(self, filepath: str): """Load persona state from file""" import json with open(filepath, 'r') as f: state = json.load(f) self.persona_generator.persona_metrics = state['persona_metrics'] self.response_generator = ResponseGenerator(state['persona_metrics']) self.response_generator.emotional_core.base_emotional_state = state['emotional_state'] # Restore interaction history for interaction in state['emotional_history']: self.emotional_memory.add_interaction( interaction['prompt'], interaction['response'], interaction['emotional_state'] ) openai numpy textblob fastapi uvicorn openai-whisper requests torch # response_generator.py from typing import Dict import numpy as np import requests from emotional_core import EmotionalCore class ResponseGenerator: def __init__(self, persona_metrics: Dict): self.persona = persona_metrics self.emotional_core = EmotionalCore( base_emotional_state=self.calculate_emotional_baseline() ) def calculate_emotional_baseline(self) -> Dict[str, float]: """Calculate baseline emotional state from persona metrics""" emotional_patterns = self.persona['emotional_baseline'] return { 'valence': np.mean([e['valence'] for e in emotional_patterns]), 'arousal': np.mean([e['arousal'] for e in emotional_patterns]), 'dominance': np.mean([e['dominance'] for e in emotional_patterns]) } def adjust_response_style(self, response: str) -> str: """Adjust response based on persona's linguistic style""" style_metrics = self.persona['response_style'] # Adjust response length target_length = style_metrics['avg_response_length'] current_length = len(response.split()) if current_length > target_length * 1.5: # Truncate response return ' '.join(response.split()[:int(target_length * 1.2)]) elif current_length < target_length * 0.5: # Expand response (you'd want more sophisticated expansion) return response + " " + self.generate_expansion(response) return response def generate_expansion(self, base_response: str) -> str: """Generate additional content to expand a response""" prompt = f"{base_response} Furthermore," expansion = self.generate_with_ollama(prompt) return expansion.replace(prompt, "") def generate_response(self, prompt: str, context: Dict = None) -> str: """Generate a response based on prompt and emotional state""" # Get current emotional state emotional_state = self.emotional_core.apply_emotional_dynamics() # Prepare prompt with emotional context emotional_prompt = self.prepare_emotional_prompt(prompt, emotional_state) # Generate base response using Ollama response = self.generate_with_ollama(emotional_prompt) # Apply style adjustments response = self.adjust_response_style(response) return response def prepare_emotional_prompt(self, prompt: str, emotional_state: Dict[str, float]) -> str: """Prepare prompt with emotional context""" emotion_descriptor = self.emotion_to_text(emotional_state) return f"[{emotion_descriptor}] {prompt}" def emotion_to_text(self, emotional_state: Dict[str, float]) -> str: """Convert emotional state to text description""" valence = emotional_state['valence'] arousal = emotional_state['arousal'] if valence > 0.3: if arousal > 0.5: return "enthusiastically" else: return "contentedly" elif valence < -0.3: if arousal > 0.5: return "angrily" else: return "sadly" else: if arousal > 0.5: return "energetically" else: return "calmly" def generate_with_ollama(self, prompt: str) -> str: """Generate a response using Ollama API""" url = 'http://localhost:11434/api/generate' # Default Ollama API endpoint data = { 'model': 'llama3.2', # Replace with your actual model name in Ollama 'prompt': prompt, 'max_tokens': 100, 'temperature': 0.8, 'top_p': 0.9 } response = requests.post(url, json=data) if response.status_code == 200: return response.json().get('response', '').strip() else: raise Exception(f"Ollama API Error: {response.status_code} {response.text}")
Sure, I can help you rewrite the application into a simpler program that works. Below is a simplified version that provides similar functionality using fewer components. This program: - Uses FastAPI to create an API with two endpoints: `/initialize` and `/chat`. - Uses Whisper to transcribe an audio file uploaded via `/initialize`. - Stores the transcript globally. - Uses OpenAI's API to generate responses in `/chat`, using the transcript as context. Here's the simplified code: ```python # app.py from fastapi import FastAPI, File, UploadFile from pydantic import BaseModel import uvicorn import openai import whisper import os app = FastAPI() # Global variable to store the transcript transcript = "" # Load Whisper model whisper_model = whisper.load_model("base") # Set your OpenAI API key openai.api_key = os.getenv("OPENAI_API_KEY") # Ensure you have set the OPENAI_API_KEY environment variable class ChatRequest(BaseModel): message: str @app.post("/initialize") async def initialize_persona(audio_file: UploadFile = File(...)): global transcript # Save uploaded file temporarily file_location = f"temp_{audio_file.filename}" with open(file_location, "wb") as file_object: file_object.write(await audio_file.read()) try: # Transcribe audio file result = whisper_model.transcribe(file_location) transcript = result["text"] # Clean up temporary file os.remove(file_location) return {"status": "success", "message": "Persona initialized successfully"} except Exception as e: return {"status": "error", "message": str(e)} @app.post("/chat") async def chat(request: ChatRequest): global transcript if not transcript: return {"status": "error", "message": "Persona not initialized"} try: # Use OpenAI API to generate a response messages = [ {"role": "system", "content": f"The following is a transcript of an interview: {transcript}"}, {"role": "user", "content": request.message} ] response = openai.ChatCompletion.create( model="gpt-3.5-turbo", # or "gpt-4" if available messages=messages, max_tokens=150, n=1, stop=None, temperature=0.7, ) answer = response.choices[0].message['content'].strip() return { "status": "success", "response": answer } except Exception as e: return {"status": "error", "message": str(e)} if __name__ == "__main__": uvicorn.run("app:app", host="0.0.0.0", port=8000) ``` **Instructions:** 1. **Install Required Packages:** ```bash pip install fastapi uvicorn openai openai-whisper ``` 2. **Set Your OpenAI API Key:** Make sure you have your OpenAI API key and set it as an environment variable: ```bash export OPENAI_API_KEY='your-api-key-here' ``` Or, you can set it directly in the code by replacing `os.getenv("OPENAI_API_KEY")` with your API key string (not recommended for security reasons). 3. **Run the Application:** ```bash uvicorn app:app --host 0.0.0.0 --port 8000 ``` 4. **Usage:** - **Initialize Persona:** Send a POST request to `/initialize` with an audio file. This will transcribe the audio and store the transcript. Example using `curl`: ```bash curl -X POST "http://localhost:8000/initialize" -F "audio_file=@path_to_your_audio_file.wav" ``` - **Chat:** Send a POST request to `/chat` with a JSON body containing your message. Example: ```bash curl -X POST "http://localhost:8000/chat" -H "Content-Type: application/json" -d '{"message": "Hello, how are you?"}' ``` The response will be a JSON containing the AI's reply. **Note:** - This simplified version removes the emotional core, emotional memory, and other complexities. - It focuses on initializing the persona from an audio file and generating responses based on that transcript. - Ensure that you have the audio file in a format supported by Whisper (e.g., WAV, MP3). - The application uses the OpenAI API, so you may incur costs depending on your usage and pricing plan. **Dependencies:** - `fastapi` - `uvicorn` - `openai` - `openai-whisper` You can install them all with: ```bash pip install fastapi uvicorn openai openai-whisper ```
o1-preview
no I want the application to use text entries and not use voice and I want it to use the locally ollama model
Certainly! Below is a simplified version of your application that uses text inputs instead of voice and utilizes a locally running Ollama model for generating responses. This application uses FastAPI to create an API with a `/chat` endpoint. ```python # app.py from fastapi import FastAPI from pydantic import BaseModel import requests import uvicorn app = FastAPI() class ChatRequest(BaseModel): message: str @app.post("/chat") async def chat(request: ChatRequest): try: # Use Ollama API to generate a response url = 'http://localhost:11434/api/generate' # Default Ollama API endpoint data = { 'model': 'your_model_name', # Replace with your actual model name in Ollama 'prompt': request.message, 'max_tokens': 150, 'temperature': 0.7, 'top_p': 0.9 } response = requests.post(url, json=data) if response.status_code == 200: # Extract the generated text from the response answer = response.json().get('output', '').strip() return { "status": "success", "response": answer } else: return { "status": "error", "message": f"Ollama API Error: {response.status_code} {response.text}" } except Exception as e: return {"status": "error", "message": str(e)} if __name__ == "__main__": uvicorn.run("app:app", host="0.0.0.0", port=8000) ``` ### Instructions: 1. **Install Required Packages:** ```bash pip install fastapi uvicorn requests ``` 2. **Set Up Ollama:** - Ensure you have [Ollama](https://ollama.ai/) installed and running locally. - Start the Ollama server: ```bash ollama serve ``` - Make sure your desired model is installed in Ollama. For example, to install the Llama 2 model: ```bash ollama pull llama2 ``` 3. **Update the Model Name:** - In the code, replace `'your_model_name'` with the actual model name you've installed in Ollama (e.g., `'llama2'`). 4. **Run the Application:** ```bash uvicorn app:app --host 0.0.0.0 --port 8000 ``` 5. **Usage:** - **Chat Endpoint:** Send a POST request to `/chat` with a JSON body containing your message. Example using `curl`: ```bash curl -X POST "http://localhost:8000/chat" -H "Content-Type: application/json" -d '{"message": "Hello, how are you?"}' ``` The response will be a JSON containing the AI's reply. ### Dependencies: - `fastapi` - `uvicorn` - `requests` You can install all dependencies with: ```bash pip install fastapi uvicorn requests ``` ### Additional Notes: - **Ollama API Endpoint:** - The default API endpoint for Ollama is `http://localhost:11434/api/generate`. If your Ollama server is running on a different host or port, update the `url` variable accordingly. - **Model Configuration:** - Adjust the `max_tokens`, `temperature`, and `top_p` parameters in the `data` dictionary to fine-tune the response generation according to your needs. - **Error Handling:** - The application includes basic error handling for API responses and exceptions. ### Example: **Request:** ```bash curl -X POST "http://localhost:8000/chat" -H "Content-Type: application/json" -d '{"message": "Tell me a joke."}' ``` **Response:** ```json { "status": "success", "response": "Why did the scarecrow win an award? Because he was outstanding in his field!" } ``` This simplified application meets your requirements by: - Accepting text inputs instead of voice. - Utilizing your locally running Ollama model for generating responses. - Providing an easy-to-use API with a `/chat` endpoint. Feel free to customize the code further to suit your specific needs.
o1-preview