| from __future__ import annotations
|
| from typing import AsyncIterable, List, Dict
|
| import requests
|
| from fastapi_poe import PoeBot, QueryRequest, PartialResponse, SettingsRequest, SettingsResponse, make_app
|
| from fastapi import Header, HTTPException
|
| from modal import Image, App, asgi_app
|
| import os
|
|
|
|
|
| NGROK_URL = "https://fca7-2601-2c1-280-1320-b881-aac7-9186-9365.ngrok-free.app"
|
| LM_STUDIO_CHAT_URL = f"{NGROK_URL}/api/v0/chat/completions"
|
| LM_STUDIO_EMBEDDINGS_URL = f"{NGROK_URL}/api/v0/embeddings"
|
|
|
|
|
| MODEL_NAME = "bartowski/Qwen2.5-Coder-32B-Instruct-GGUF/Qwen2.5-Coder-32B-Instruct-IQ2_M.gguf"
|
|
|
|
|
| NEW_BOT_ACCESS_KEY = "Kskn3sHdJh7nkVWGcpwcGOIHYSrsML3l"
|
|
|
|
|
| user_histories: Dict[str, List[dict]] = {}
|
|
|
| class main(PoeBot):
|
| async def get_response(
|
| self, request: QueryRequest, authorization: str = Header(...)
|
| ) -> AsyncIterable[PartialResponse]:
|
| """
|
| Handle user queries dynamically while validating the Poe access key.
|
| """
|
|
|
| if authorization != NEW_BOT_ACCESS_KEY:
|
| print("Warning: Unauthorized access key used.")
|
|
|
|
|
|
|
| user_id = request.user_id if hasattr(request, "user_id") else str(hash(request))
|
| if not user_id:
|
| yield PartialResponse(text="Error: User identifier not provided.")
|
| return
|
|
|
|
|
| user_message = request.query[-1].content
|
|
|
|
|
| if user_id not in user_histories:
|
| user_histories[user_id] = []
|
| conversation_history = user_histories[user_id]
|
|
|
| try:
|
|
|
| conversation_history.append({"role": "user", "content": user_message})
|
|
|
|
|
| response_text = self.get_chat_completion(conversation_history)
|
|
|
|
|
| conversation_history.append({"role": "assistant", "content": response_text})
|
|
|
|
|
| yield PartialResponse(text=response_text.strip())
|
| except Exception as e:
|
|
|
| yield PartialResponse(text=f"An error occurred: {e}")
|
|
|
| def get_chat_completion(self, messages: List[dict]) -> str:
|
| """
|
| Send a chat completion request to LM Studio's /api/v0/chat/completions endpoint.
|
| """
|
| payload = {
|
| "model": MODEL_NAME,
|
| "messages": messages,
|
| "temperature": 0.7,
|
| "max_tokens": 1024,
|
| "stream": False
|
| }
|
| response = requests.post(LM_STUDIO_CHAT_URL, json=payload, timeout=30)
|
| response.raise_for_status()
|
| generated_text = response.json().get("choices", [{}])[0].get("message", {}).get("content", "")
|
|
|
|
|
| if not generated_text:
|
| generated_text = "I'm sorry, I couldn't generate a response. Could you please try again?"
|
|
|
| return generated_text
|
|
|
| def get_embeddings(self, text: str) -> str:
|
| """
|
| Generate text embeddings using LM Studio's /api/v0/embeddings endpoint.
|
| """
|
| payload = {"model": "openai/clip-vit-base-patch32", "input": text}
|
| response = requests.post(LM_STUDIO_EMBEDDINGS_URL, json=payload, timeout=10)
|
| response.raise_for_status()
|
| embedding = response.json().get("data", [{}])[0].get("embedding", [])
|
| return f"Embeddings: {embedding}"
|
|
|
| async def get_settings(self, setting: SettingsRequest) -> SettingsResponse:
|
| """
|
| Configure the bot's capabilities for Poe, such as enabling attachments.
|
| """
|
| return SettingsResponse(
|
| allow_attachments=False,
|
| )
|
|
|
|
|
| REQUIREMENTS = ["fastapi-poe==0.0.24", "requests==2.31.0"]
|
| image = Image.debian_slim().pip_install(REQUIREMENTS)
|
| new_app = App("another-secure-lmstudio-poe-bot")
|
|
|
| @new_app.function(image=image)
|
| @asgi_app()
|
| def fastapi_app():
|
| bot = AnotherSecureLMStudioBot()
|
| return make_app(bot, allow_without_key=True)
|
|
|