fix: better repo name generation, refs NOISSUE
This commit is contained in:
@@ -18,6 +18,14 @@ except ImportError:
|
||||
class RequestInterpreter:
|
||||
"""Use Ollama to turn free-form text into a structured software request."""
|
||||
|
||||
REQUEST_PREFIX_WORDS = {
|
||||
'a', 'an', 'app', 'application', 'build', 'create', 'dashboard', 'develop', 'design', 'for', 'generate',
|
||||
'internal', 'make', 'me', 'modern', 'need', 'new', 'our', 'platform', 'please', 'project', 'service',
|
||||
'simple', 'site', 'start', 'system', 'the', 'tool', 'us', 'want', 'web', 'website', 'with',
|
||||
}
|
||||
|
||||
REPO_NOISE_WORDS = REQUEST_PREFIX_WORDS | {'and', 'from', 'into', 'on', 'that', 'this', 'to'}
|
||||
|
||||
def __init__(self, ollama_url: str | None = None, model: str | None = None):
|
||||
self.ollama_url = (ollama_url or settings.ollama_url).rstrip('/')
|
||||
self.model = model or settings.OLLAMA_MODEL
|
||||
@@ -301,6 +309,7 @@ class RequestInterpreter:
|
||||
"""Normalize a candidate project name into a readable title."""
|
||||
cleaned = re.sub(r'[^A-Za-z0-9\s-]+', ' ', raw_name).strip(' -')
|
||||
cleaned = re.sub(r'\s+', ' ', cleaned)
|
||||
cleaned = self._trim_request_prefix(cleaned)
|
||||
special_upper = {'api', 'crm', 'erp', 'cms', 'hr', 'it', 'ui', 'qa'}
|
||||
words = []
|
||||
for word in cleaned.split()[:6]:
|
||||
@@ -308,14 +317,49 @@ class RequestInterpreter:
|
||||
words.append(lowered.upper() if lowered in special_upper else lowered.capitalize())
|
||||
return ' '.join(words) or 'Generated Project'
|
||||
|
||||
def _trim_request_prefix(self, candidate: str) -> str:
|
||||
"""Remove leading request phrasing from model-produced names and slugs."""
|
||||
tokens = [token for token in re.split(r'[-\s]+', candidate or '') if token]
|
||||
while tokens and tokens[0].lower() in self.REQUEST_PREFIX_WORDS:
|
||||
tokens.pop(0)
|
||||
trimmed = ' '.join(tokens).strip()
|
||||
return trimmed or candidate.strip()
|
||||
|
||||
def _derive_repo_name(self, project_name: str) -> str:
|
||||
"""Derive a repository slug from a human-readable project name."""
|
||||
preferred = (project_name or 'project').strip().lower().replace(' ', '-')
|
||||
preferred_name = self._trim_request_prefix((project_name or 'project').strip())
|
||||
preferred = preferred_name.lower().replace(' ', '-')
|
||||
sanitized = ''.join(ch if ch.isalnum() or ch in {'-', '_'} else '-' for ch in preferred)
|
||||
while '--' in sanitized:
|
||||
sanitized = sanitized.replace('--', '-')
|
||||
return sanitized.strip('-') or 'project'
|
||||
|
||||
def _should_use_repo_name_candidate(self, candidate: str, project_name: str) -> bool:
|
||||
"""Return whether a model-proposed repo slug is concise enough to trust directly."""
|
||||
cleaned = self._trim_request_prefix(re.sub(r'[^A-Za-z0-9\s_-]+', ' ', candidate or '').strip())
|
||||
if not cleaned:
|
||||
return False
|
||||
candidate_tokens = [token.lower() for token in re.split(r'[-\s_]+', cleaned) if token]
|
||||
if not candidate_tokens:
|
||||
return False
|
||||
if len(candidate_tokens) > 6:
|
||||
return False
|
||||
noise_count = sum(1 for token in candidate_tokens if token in self.REPO_NOISE_WORDS)
|
||||
if noise_count >= 2:
|
||||
return False
|
||||
if len('-'.join(candidate_tokens)) > 40:
|
||||
return False
|
||||
project_tokens = {
|
||||
token.lower()
|
||||
for token in re.split(r'[-\s_]+', project_name or '')
|
||||
if token and token.lower() not in self.REPO_NOISE_WORDS
|
||||
}
|
||||
if project_tokens:
|
||||
overlap = sum(1 for token in candidate_tokens if token in project_tokens)
|
||||
if overlap == 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _ensure_unique_repo_name(self, repo_name: str, reserved_names: set[str]) -> str:
|
||||
"""Choose a repository slug that does not collide with tracked or remote repositories."""
|
||||
base_name = self._derive_repo_name(repo_name)
|
||||
@@ -329,7 +373,10 @@ class RequestInterpreter:
|
||||
def _normalize_project_identity(self, payload: dict, fallback_name: str) -> tuple[str, str]:
|
||||
"""Normalize model-proposed project and repository naming."""
|
||||
project_name = self._humanize_name(str(payload.get('project_name') or payload.get('name') or fallback_name))
|
||||
repo_name = self._derive_repo_name(str(payload.get('repo_name') or project_name))
|
||||
repo_candidate = str(payload.get('repo_name') or '').strip()
|
||||
repo_name = self._derive_repo_name(project_name)
|
||||
if repo_candidate and self._should_use_repo_name_candidate(repo_candidate, project_name):
|
||||
repo_name = self._derive_repo_name(repo_candidate)
|
||||
return project_name, repo_name
|
||||
|
||||
def _heuristic_fallback(self, prompt_text: str, context: dict | None = None) -> tuple[dict, dict]:
|
||||
|
||||
@@ -798,6 +798,7 @@ def get_llm_prompt_settings(db: DbSession):
|
||||
@app.put('/llm/prompts/{prompt_key}')
|
||||
def update_llm_prompt_setting(prompt_key: str, request: LLMPromptSettingUpdateRequest, db: DbSession):
|
||||
"""Persist one editable LLM prompt override into the database."""
|
||||
database_module.init_db()
|
||||
result = DatabaseManager(db).save_llm_prompt_setting(prompt_key, request.value, actor='api')
|
||||
if result.get('status') == 'error':
|
||||
raise HTTPException(status_code=400, detail=result.get('message', 'Prompt save failed'))
|
||||
@@ -807,6 +808,7 @@ def update_llm_prompt_setting(prompt_key: str, request: LLMPromptSettingUpdateRe
|
||||
@app.delete('/llm/prompts/{prompt_key}')
|
||||
def reset_llm_prompt_setting(prompt_key: str, db: DbSession):
|
||||
"""Reset one editable LLM prompt override back to the environment/default value."""
|
||||
database_module.init_db()
|
||||
result = DatabaseManager(db).reset_llm_prompt_setting(prompt_key, actor='api')
|
||||
if result.get('status') == 'error':
|
||||
raise HTTPException(status_code=400, detail=result.get('message', 'Prompt reset failed'))
|
||||
|
||||
Reference in New Issue
Block a user