File size: 9,508 Bytes
b22fc56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# storyverse_weaver/core/llm_services.py
import os
import google.generativeai as genai
from huggingface_hub import InferenceClient
# from dotenv import load_dotenv # Optional: for local .env file
# load_dotenv() # Load environment variables from .env file if present

GOOGLE_API_KEY = os.getenv("STORYVERSE_GOOGLE_API_KEY") # Use specific env var names
HF_TOKEN = os.getenv("STORYVERSE_HF_TOKEN")

GEMINI_TEXT_CONFIGURED = False
HF_TEXT_CONFIGURED = False
hf_inference_text_client = None

class LLMTextResponse:
    def __init__(self, text=None, error=None, success=True, model_id_used="unknown_text_llm"):
        self.text, self.error, self.success, self.model_id_used = text, error, success, model_id_used

def initialize_text_llms():
    global GOOGLE_API_KEY, HF_TOKEN, GEMINI_TEXT_CONFIGURED, HF_TEXT_CONFIGURED, hf_inference_text_client
    print("INFO: llm_services.py - Initializing Text LLM clients...")
    if GOOGLE_API_KEY and GOOGLE_API_KEY.strip():
        try:
            genai.configure(api_key=GOOGLE_API_KEY)
            GEMINI_TEXT_CONFIGURED = True
            print("SUCCESS: llm_services.py - Google Gemini API (for text) configured.")
        except Exception as e:
            print(f"ERROR: llm_services.py - Failed to configure Google Gemini API: {e}")
            GEMINI_TEXT_CONFIGURED = False
    else:
        print("WARNING: llm_services.py - STORYVERSE_GOOGLE_API_KEY not found or empty.")
        GEMINI_TEXT_CONFIGURED = False

    if HF_TOKEN and HF_TOKEN.strip():
        try:
            hf_inference_text_client = InferenceClient(token=HF_TOKEN)
            HF_TEXT_CONFIGURED = True
            print("SUCCESS: llm_services.py - Hugging Face InferenceClient (for text) initialized.")
        except Exception as e:
            print(f"ERROR: llm_services.py - Failed to initialize HF InferenceClient: {e}")
            HF_TEXT_CONFIGURED = False
    else:
        print("WARNING: llm_services.py - STORYVERSE_HF_TOKEN not found or empty.")
        HF_TEXT_CONFIGURED = False
    print(f"INFO: llm_services.py - Text LLM Init complete. Gemini Text: {GEMINI_TEXT_CONFIGURED}, HF Text: {HF_TEXT_CONFIGURED}")

def is_gemini_text_ready(): return GEMINI_TEXT_CONFIGURED
def is_hf_text_ready(): return HF_TEXT_CONFIGURED

def generate_text_gemini(prompt: str, model_id: str = "gemini-1.5-flash-latest", system_prompt: str = None, temperature: float = 0.7, max_tokens: int = 512) -> LLMTextResponse:
    if not is_gemini_text_ready():
        return LLMTextResponse(error="Gemini text API not configured.", success=False, model_id_used=model_id)
    try:
        model = genai.GenerativeModel(model_name=model_id, system_instruction=system_prompt)
        config = genai.types.GenerationConfig(temperature=temperature, max_output_tokens=max_tokens)
        response = model.generate_content(prompt, generation_config=config)
        # Add robust response checking as in AlgoForge's llm_clients.py
        if response.prompt_feedback and response.prompt_feedback.block_reason:
            return LLMTextResponse(error=f"Gemini: Prompt blocked ({response.prompt_feedback.block_reason})", success=False, model_id_used=model_id)
        if not response.candidates or not response.candidates[0].content.parts:
            return LLMTextResponse(error=f"Gemini: No content generated (Finish reason: {response.candidates[0].finish_reason if response.candidates else 'Unknown'})", success=False, model_id_used=model_id)
        return LLMTextResponse(text=response.text, model_id_used=model_id)
    except Exception as e:
        return LLMTextResponse(error=f"Gemini API Error ({model_id}): {type(e).__name__} - {str(e)}", success=False, model_id_used=model_id)

def generate_text_hf(prompt: str, model_id: str = "mistralai/Mistral-7B-Instruct-v0.2", system_prompt: str = None, temperature: float = 0.7, max_tokens: int = 512) -> LLMTextResponse:
    if not is_hf_text_ready() or not hf_inference_text_client:
        return LLMTextResponse(error="HF text API not configured.", success=False, model_id_used=model_id)
    
    full_prompt = f"<s>[INST] <<SYS>>\n{system_prompt}\n<</SYS>>\n\n{prompt} [/INST]" if system_prompt else prompt
    try:
        use_sample = temperature > 0.001
        response_text = hf_inference_text_client.text_generation(
            full_prompt, model=model_id, max_new_tokens=max_tokens,
            temperature=temperature if use_sample else None, do_sample=use_sample
        )
        return LLMTextResponse(text=response_text, model_id_used=model_id)
    except Exception as e:
        return LLMTextResponse(error=f"HF API Error ({model_id}): {type(e).__name__} - {str(e)}", success=False, model_id_used=model_id)

print("DEBUG: core.llm_services (for StoryVerseWeaver) - Module defined.")# storyverse_weaver/core/llm_services.py
import os
import google.generativeai as genai
from huggingface_hub import InferenceClient
# from dotenv import load_dotenv # Optional: for local .env file
# load_dotenv() # Load environment variables from .env file if present

GOOGLE_API_KEY = os.getenv("STORYVERSE_GOOGLE_API_KEY") # Use specific env var names
HF_TOKEN = os.getenv("STORYVERSE_HF_TOKEN")

GEMINI_TEXT_CONFIGURED = False
HF_TEXT_CONFIGURED = False
hf_inference_text_client = None

class LLMTextResponse:
    def __init__(self, text=None, error=None, success=True, model_id_used="unknown_text_llm"):
        self.text, self.error, self.success, self.model_id_used = text, error, success, model_id_used

def initialize_text_llms():
    global GOOGLE_API_KEY, HF_TOKEN, GEMINI_TEXT_CONFIGURED, HF_TEXT_CONFIGURED, hf_inference_text_client
    print("INFO: llm_services.py - Initializing Text LLM clients...")
    if GOOGLE_API_KEY and GOOGLE_API_KEY.strip():
        try:
            genai.configure(api_key=GOOGLE_API_KEY)
            GEMINI_TEXT_CONFIGURED = True
            print("SUCCESS: llm_services.py - Google Gemini API (for text) configured.")
        except Exception as e:
            print(f"ERROR: llm_services.py - Failed to configure Google Gemini API: {e}")
            GEMINI_TEXT_CONFIGURED = False
    else:
        print("WARNING: llm_services.py - STORYVERSE_GOOGLE_API_KEY not found or empty.")
        GEMINI_TEXT_CONFIGURED = False

    if HF_TOKEN and HF_TOKEN.strip():
        try:
            hf_inference_text_client = InferenceClient(token=HF_TOKEN)
            HF_TEXT_CONFIGURED = True
            print("SUCCESS: llm_services.py - Hugging Face InferenceClient (for text) initialized.")
        except Exception as e:
            print(f"ERROR: llm_services.py - Failed to initialize HF InferenceClient: {e}")
            HF_TEXT_CONFIGURED = False
    else:
        print("WARNING: llm_services.py - STORYVERSE_HF_TOKEN not found or empty.")
        HF_TEXT_CONFIGURED = False
    print(f"INFO: llm_services.py - Text LLM Init complete. Gemini Text: {GEMINI_TEXT_CONFIGURED}, HF Text: {HF_TEXT_CONFIGURED}")

def is_gemini_text_ready(): return GEMINI_TEXT_CONFIGURED
def is_hf_text_ready(): return HF_TEXT_CONFIGURED

def generate_text_gemini(prompt: str, model_id: str = "gemini-1.5-flash-latest", system_prompt: str = None, temperature: float = 0.7, max_tokens: int = 512) -> LLMTextResponse:
    if not is_gemini_text_ready():
        return LLMTextResponse(error="Gemini text API not configured.", success=False, model_id_used=model_id)
    try:
        model = genai.GenerativeModel(model_name=model_id, system_instruction=system_prompt)
        config = genai.types.GenerationConfig(temperature=temperature, max_output_tokens=max_tokens)
        response = model.generate_content(prompt, generation_config=config)
        # Add robust response checking as in AlgoForge's llm_clients.py
        if response.prompt_feedback and response.prompt_feedback.block_reason:
            return LLMTextResponse(error=f"Gemini: Prompt blocked ({response.prompt_feedback.block_reason})", success=False, model_id_used=model_id)
        if not response.candidates or not response.candidates[0].content.parts:
            return LLMTextResponse(error=f"Gemini: No content generated (Finish reason: {response.candidates[0].finish_reason if response.candidates else 'Unknown'})", success=False, model_id_used=model_id)
        return LLMTextResponse(text=response.text, model_id_used=model_id)
    except Exception as e:
        return LLMTextResponse(error=f"Gemini API Error ({model_id}): {type(e).__name__} - {str(e)}", success=False, model_id_used=model_id)

def generate_text_hf(prompt: str, model_id: str = "mistralai/Mistral-7B-Instruct-v0.2", system_prompt: str = None, temperature: float = 0.7, max_tokens: int = 512) -> LLMTextResponse:
    if not is_hf_text_ready() or not hf_inference_text_client:
        return LLMTextResponse(error="HF text API not configured.", success=False, model_id_used=model_id)
    
    full_prompt = f"<s>[INST] <<SYS>>\n{system_prompt}\n<</SYS>>\n\n{prompt} [/INST]" if system_prompt else prompt
    try:
        use_sample = temperature > 0.001
        response_text = hf_inference_text_client.text_generation(
            full_prompt, model=model_id, max_new_tokens=max_tokens,
            temperature=temperature if use_sample else None, do_sample=use_sample
        )
        return LLMTextResponse(text=response_text, model_id_used=model_id)
    except Exception as e:
        return LLMTextResponse(error=f"HF API Error ({model_id}): {type(e).__name__} - {str(e)}", success=False, model_id_used=model_id)

print("DEBUG: core.llm_services (for StoryVerseWeaver) - Module defined.")