Skip to content

Commit 57bad3e

Browse files
committed
Merge dev changes from Aug 7 to Sep 17: Refactor, OpenAI support, and concurrency parameters
2 parents 5e18f3a + 06537b4 commit 57bad3e

24 files changed

+1774
-995
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ qa_pairs*
5555
Khauneesh/
5656
*job_args*
5757

58+
# Generated data files
59+
freeform_data_*.json
60+
row_data_*.json
61+
lending_*.json
62+
seeds_*.json
63+
SeedsInstructions.json
64+
*_example.json
65+
nm.json
66+
french_input.json
67+
5868
# DB
5969
*metadata.db-shm
6070
*metadata.db-wal

app/client/src/pages/DataGenerator/Finish.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,8 @@ const Finish = () => {
255255
title: 'Review Dataset',
256256
description: 'Review your dataset to ensure it properly fits your usecase.',
257257
icon: <GradingIcon/>,
258-
href: getFilesURL(genDatasetResp?.export_path?.local || "")
258+
href: getFilesURL(genDatasetResp?.export_path?.local || ""),
259+
external: true
259260
},
260261
{
261262
avatar: '',
@@ -278,7 +279,8 @@ const Finish = () => {
278279
title: 'Review Dataset',
279280
description: 'Once your dataset finishes generating, you can review your dataset in the workbench files',
280281
icon: <GradingIcon/>,
281-
href: getFilesURL('')
282+
href: getFilesURL(''),
283+
external: true
282284
},
283285
{
284286
avatar: '',
@@ -361,7 +363,18 @@ const Finish = () => {
361363
<List
362364
itemLayout="horizontal"
363365
dataSource={isDemo ? nextStepsListPreview : nextStepsListNonPreview}
364-
renderItem={({ title, href, icon, description}, i) => (
366+
renderItem={({ title, href, icon, description, external }, i) => (
367+
external ?
368+
<Link to={href} target="_blank" rel="noopener noreferrer">
369+
<List.Item key={`${title}-${i}`}>
370+
<List.Item.Meta
371+
avatar={<Avatar style={{ backgroundColor: '#1677ff'}} icon={icon} />}
372+
title={title}
373+
description={description}
374+
/>
375+
</List.Item>
376+
</Link> :
377+
365378
<Link to={href}>
366379
<List.Item key={`${title}-${i}`}>
367380
<List.Item.Meta

app/client/src/pages/Home/TemplateCard.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,10 @@ const TagsContainer = styled.div`
132132
}
133133
`;
134134

135-
const StyledTag = styled(Tag)`
136-
color: ${props => props.theme.color};
137-
background-color: ${props => props.theme.backgroundColor};
138-
border: 1px solid ${props => props.theme.borderColor};
135+
const StyledTag = styled(Tag)<{ $theme: { color: string; backgroundColor: string; borderColor: string } }>`
136+
color: ${props => props.$theme.color} !important;
137+
background-color: ${props => props.$theme.backgroundColor} !important;
138+
border: 1px solid ${props => props.$theme.borderColor} !important;
139139
`;
140140

141141

@@ -150,7 +150,7 @@ const TemplateCard: React.FC<Props> = ({ template }) => {
150150
const { color, backgroundColor, borderColor } = getTemplateTagColors(theme as string);
151151

152152
return (
153-
<StyledTag key={tag} theme={{ color, backgroundColor, borderColor }}>
153+
<StyledTag key={tag} $theme={{ color, backgroundColor, borderColor }}>
154154
<div className="tag-title" title={tag} style={{ maxWidth: '150px', color }}>
155155
{tag}
156156
</div>

app/core/model_handlers.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ def generate_response(
180180
return self._handle_caii_request(prompt)
181181
if self.inference_type == "openai":
182182
return self._handle_openai_request(prompt)
183+
if self.inference_type == "openai_compatible":
184+
return self._handle_openai_compatible_request(prompt)
183185
if self.inference_type == "gemini":
184186
return self._handle_gemini_request(prompt)
185187
raise ModelHandlerError(f"Unsupported inference_type={self.inference_type}", 400)
@@ -342,6 +344,66 @@ def _handle_openai_request(self, prompt: str):
342344
except Exception as e:
343345
raise ModelHandlerError(f"OpenAI request failed: {e}", 500)
344346

347+
# ---------- OpenAI Compatible -------------------------------------------------------
348+
def _handle_openai_compatible_request(self, prompt: str):
349+
"""Handle OpenAI compatible endpoints with proper timeout configuration"""
350+
try:
351+
import httpx
352+
from openai import OpenAI
353+
354+
# Get API key from environment variable (only credential needed)
355+
api_key = os.getenv('OpenAI_Endpoint_Compatible_Key')
356+
if not api_key:
357+
raise ModelHandlerError("OpenAI_Endpoint_Compatible_Key environment variable not set", 500)
358+
359+
# Base URL comes from caii_endpoint parameter (passed during initialization)
360+
openai_compatible_endpoint = self.caii_endpoint
361+
if not openai_compatible_endpoint:
362+
raise ModelHandlerError("OpenAI compatible endpoint not provided", 500)
363+
364+
# Configure timeout for OpenAI compatible client (same as OpenAI v1.57.2)
365+
timeout_config = httpx.Timeout(
366+
connect=self.OPENAI_CONNECT_TIMEOUT,
367+
read=self.OPENAI_READ_TIMEOUT,
368+
write=10.0,
369+
pool=5.0
370+
)
371+
372+
# Configure httpx client with certificate verification for private cloud
373+
if os.path.exists("/etc/ssl/certs/ca-certificates.crt"):
374+
http_client = httpx.Client(
375+
verify="/etc/ssl/certs/ca-certificates.crt",
376+
timeout=timeout_config
377+
)
378+
else:
379+
http_client = httpx.Client(timeout=timeout_config)
380+
381+
# Remove trailing '/chat/completions' if present (similar to CAII handling)
382+
openai_compatible_endpoint = openai_compatible_endpoint.removesuffix('/chat/completions')
383+
384+
client = OpenAI(
385+
api_key=api_key,
386+
base_url=openai_compatible_endpoint,
387+
http_client=http_client
388+
)
389+
390+
completion = client.chat.completions.create(
391+
model=self.model_id,
392+
messages=[{"role": "user", "content": prompt}],
393+
max_tokens=self.model_params.max_tokens,
394+
temperature=self.model_params.temperature,
395+
top_p=self.model_params.top_p,
396+
stream=False,
397+
)
398+
399+
print("generated via OpenAI Compatible endpoint")
400+
response_text = completion.choices[0].message.content
401+
402+
return self._extract_json_from_text(response_text) if not self.custom_p else response_text
403+
404+
except Exception as e:
405+
raise ModelHandlerError(f"OpenAI Compatible request failed: {str(e)}", status_code=500)
406+
345407
# ---------- Gemini -------------------------------------------------------
346408
def _handle_gemini_request(self, prompt: str):
347409
if genai is None:

app/main.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@
4242
sys.path.append(str(ROOT_DIR))
4343

4444
from app.services.evaluator_service import EvaluatorService
45+
from app.services.evaluator_legacy_service import EvaluatorLegacyService
4546
from app.models.request_models import SynthesisRequest, EvaluationRequest, Export_synth, ModelParameters, CustomPromptRequest, JsonDataSize, RelativePath, Technique
4647
from app.services.synthesis_service import SynthesisService
48+
from app.services.synthesis_legacy_service import SynthesisLegacyService
4749
from app.services.export_results import Export_Service
4850

4951
from app.core.prompt_templates import PromptBuilder, PromptHandler
@@ -66,8 +68,10 @@
6668
#****************************************Initialize************************************************
6769

6870
# Initialize services
69-
synthesis_service = SynthesisService()
70-
evaluator_service = EvaluatorService()
71+
synthesis_service = SynthesisService() # Freeform only
72+
synthesis_legacy_service = SynthesisLegacyService() # SFT and Custom_Workflow
73+
evaluator_service = EvaluatorService() # Freeform only
74+
evaluator_legacy_service = EvaluatorLegacyService() # SFT and Custom_Workflow
7175
export_service = Export_Service()
7276
db_manager = DatabaseManager()
7377

@@ -552,9 +556,11 @@ async def generate_examples(request: SynthesisRequest):
552556

553557
if is_demo== True:
554558
if request.input_path:
555-
return await synthesis_service.generate_result(request,is_demo, request_id=request_id)
559+
# Custom_Workflow technique - route to legacy service
560+
return await synthesis_legacy_service.generate_result(request,is_demo, request_id=request_id)
556561
else:
557-
return await synthesis_service.generate_examples(request,is_demo, request_id=request_id)
562+
# SFT technique - route to legacy service
563+
return await synthesis_legacy_service.generate_examples(request,is_demo, request_id=request_id)
558564
else:
559565
return synthesis_job.generate_job(request, core, mem, request_id=request_id)
560566

@@ -626,7 +632,8 @@ async def evaluate_examples(request: EvaluationRequest):
626632

627633
is_demo = request.is_demo
628634
if is_demo:
629-
return evaluator_service.evaluate_results(request, request_id=request_id)
635+
# SFT and Custom_Workflow evaluation - route to legacy service
636+
return evaluator_legacy_service.evaluate_results(request, request_id=request_id)
630637

631638
else:
632639
return synthesis_job.evaluate_job(request, request_id=request_id)
@@ -1242,7 +1249,7 @@ def is_empty(self):
12421249
async def health_check():
12431250
"""Get API health status"""
12441251
#return {"status": "healthy"}
1245-
return synthesis_service.get_health_check()
1252+
return synthesis_legacy_service.get_health_check()
12461253

12471254
@app.get("/{use_case}/example_payloads")
12481255
async def get_example_payloads(use_case:UseCase):
@@ -1255,6 +1262,7 @@ async def get_example_payloads(use_case:UseCase):
12551262
"technique": "sft",
12561263
"topics": ["python_basics", "data_structures"],
12571264
"is_demo": True,
1265+
"max_concurrent_topics": 5,
12581266
"examples": [
12591267
{
12601268
"question": "How do you create a list in Python and add elements to it?",
@@ -1281,6 +1289,7 @@ async def get_example_payloads(use_case:UseCase):
12811289
"technique": "sft",
12821290
"topics": ["basic_queries", "joins"],
12831291
"is_demo": True,
1292+
"max_concurrent_topics": 5,
12841293
"schema": "CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(100), email VARCHAR(255));\nCREATE TABLE orders (id INT PRIMARY KEY, user_id INT, amount DECIMAL(10,2), FOREIGN KEY (user_id) REFERENCES users(id));",
12851294
"examples":[
12861295
{
@@ -1309,6 +1318,7 @@ async def get_example_payloads(use_case:UseCase):
13091318
"topics": ["topic 1", "topic 2"],
13101319
"custom_prompt": "Give your instructions here",
13111320
"is_demo": True,
1321+
"max_concurrent_topics": 5,
13121322

13131323
"examples":[
13141324
{

app/models/request_models.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ class SynthesisRequest(BaseModel):
123123
# Optional fields that can override defaults
124124
inference_type: Optional[str] = "aws_bedrock"
125125
caii_endpoint: Optional[str] = None
126+
openai_compatible_endpoint: Optional[str] = None
126127
topics: Optional[List[str]] = None
127128
doc_paths: Optional[List[str]] = None
128129
input_path: Optional[List[str]] = None
@@ -137,7 +138,13 @@ class SynthesisRequest(BaseModel):
137138
example_path: Optional[str] = None
138139
schema: Optional[str] = None # Added schema field
139140
custom_prompt: Optional[str] = None
140-
display_name: Optional[str] = None
141+
display_name: Optional[str] = None
142+
max_concurrent_topics: Optional[int] = Field(
143+
default=5,
144+
ge=1,
145+
le=100,
146+
description="Maximum number of concurrent topics to process (1-100)"
147+
)
141148

142149
# Optional model parameters with defaults
143150
model_params: Optional[ModelParameters] = Field(
@@ -155,7 +162,7 @@ class SynthesisRequest(BaseModel):
155162
"technique": "sft",
156163
"topics": ["python_basics", "data_structures"],
157164
"is_demo": True,
158-
165+
"max_concurrent_topics": 5
159166

160167
}
161168
}
@@ -208,6 +215,12 @@ class EvaluationRequest(BaseModel):
208215
display_name: Optional[str] = None
209216
output_key: Optional[str] = 'Prompt'
210217
output_value: Optional[str] = 'Completion'
218+
max_workers: Optional[int] = Field(
219+
default=4,
220+
ge=1,
221+
le=100,
222+
description="Maximum number of worker threads for parallel evaluation (1-100)"
223+
)
211224

212225
# Export configuration
213226
export_type: str = "local" # "local" or "s3"
@@ -226,7 +239,8 @@ class EvaluationRequest(BaseModel):
226239
"inference_type": "aws_bedrock",
227240
"import_path": "qa_pairs_llama3-1-70b-instruct-v1:0_20241114_212837_test.json",
228241
"import_type": "local",
229-
"export_type":"local"
242+
"export_type":"local",
243+
"max_workers": 4
230244

231245
}
232246
}

app/run_eval_job.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from app.models.request_models import EvaluationRequest, ModelParameters
3232

3333
from app.services.evaluator_service import EvaluatorService
34+
from app.services.evaluator_legacy_service import EvaluatorLegacyService
3435
import asyncio
3536
import nest_asyncio
3637

@@ -40,7 +41,7 @@
4041
async def run_eval(request, job_name, request_id):
4142
try:
4243

43-
job = EvaluatorService()
44+
job = EvaluatorLegacyService()
4445
result = job.evaluate_results(request,job_name, is_demo=False, request_id=request_id)
4546
return result
4647
except Exception as e:

app/run_job.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import json
3333
from app.models.request_models import SynthesisRequest
3434
from app.services.synthesis_service import SynthesisService
35+
from app.services.synthesis_legacy_service import SynthesisLegacyService
3536
import asyncio
3637
import nest_asyncio # Add this import
3738

@@ -41,7 +42,7 @@
4142
async def run_synthesis(request, job_name, request_id):
4243
"""Run standard synthesis job for question-answer pairs"""
4344
try:
44-
job = SynthesisService()
45+
job = SynthesisLegacyService()
4546
if request.input_path:
4647
result = await job.generate_result(request, job_name, is_demo=False, request_id=request_id)
4748
else:

0 commit comments

Comments
 (0)