{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Classify feedback with an uncertainty bucket\n",
        "Run in a permitted hosted notebook; no local/browser AI download is required. This is a small educational reference, not a real provider benchmark.\n",
        "Optional dependencies for this fixture: # Standard library only for the supplied reference.\n\n",
        "For learners across regions underserved or excluded by mainstream providers: verify country eligibility, language, account/identity requirements, data terms, cost, quota and connectivity before choosing a cloud service. Use only legitimate available alternatives; never bypass restrictions or invent a country/account. No service access? Complete the labelled manual/fixture route without claiming a live AI run."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "\"\"\"Deterministic educational references; no live AI calls, credentials or network.\nRun model exercises only in a permitted hosted runtime. Synthetic wiring tests are\nnot production benchmarks, independent assessment or real-world validation.\n\"\"\"\nimport math,re,statistics,itertools,copy\n\ndef numeric(x):return isinstance(x,(int,float)) and not isinstance(x,bool) and math.isfinite(x)\ndef run(kind,d):\n if not isinstance(d,dict):raise ValueError('Input must be an object.')\n if kind in ['reproducible-cloud-lab','python-records','data-cleaning']:\n  accepted=[];rejected=[];reasons=[];seen=set()\n  for r in d['rows']:\n   reason='duplicate_id' if r['id'] in seen else 'non_numeric' if not numeric(r.get('amount')) else 'negative_amount' if r['amount']<0 else None\n   if reason:rejected.append(r['id']);reasons.append(reason)\n   else:seen.add(r['id']);accepted.append(r)\n  result={'accepted':len(accepted),'total':sum(r['amount'] for r in accepted)}\n  result.update({'reasons':reasons} if kind=='data-cleaning' else {'rejected':rejected});return result\n if kind=='visual-brief':\n  failed=[k for k,v in d['brief'].items() if d['candidate'].get(k)!=v];return {'passed':len(d['brief'])-len(failed),'failed':failed,'decision':'revise' if failed else 'approve_spec_only'}\n if kind=='measured-ml':\n  truth,pred=d['truth'],d['predicted']\n  if not truth or len(truth)!=len(pred) or any(x not in [0,1] for x in truth+pred):raise ValueError('Equal nonempty binary lists required.')\n  correct=sum(a==b for a,b in zip(truth,pred));return {'correct':correct,'total':len(truth),'accuracy':round(correct/len(truth),6),'baseline_accuracy':max(truth.count(0),truth.count(1))/len(truth),'false_positive':sum(a==0 and b==1 for a,b in zip(truth,pred)),'false_negative':sum(a==1 and b==0 for a,b in zip(truth,pred))}\n if kind=='generative-workbench':\n  scores={r['id']:int(r['facts'])+int(r['format'])+int(not r['invented_discount']) for r in d['candidates']};return {'scores':scores,'selected':max(scores,key=scores.get)}\n if kind=='evidence-assistant':\n  answers=[]\n  for q in d['questions']:\n   source=q['evidence'] if q.get('evidence') in d['source'] else None;answers.append({'id':q['id'],'status':'supported' if source else 'unknown','citation':source})\n  return {'answers':answers}\n if kind=='ai-fieldwork':\n  manual=sum(d['manual_minutes']);assisted=sum(d['assisted_minutes'])+sum(d['checking_minutes']);saving=manual-assisted;return {'manual_total':manual,'assisted_total':assisted,'saved_minutes':saving,'claim':'no measured time saving' if saving==0 else 'observed sample only'}\n if kind=='faq-assistant':return {'routes':{m['id']:'draft_with_source' if m['type']=='known_faq' else 'human_review' for m in d['messages']},'automatic_actions':0}\n if kind=='data-report':\n  cats={}\n  for r in d['rows']:cats[r['category']]=cats.get(r['category'],0)+r['amount']\n  return {'rows':len(d['rows']),'categories':cats,'total':sum(cats.values())}\n if kind=='algorithms-lab':\n  values=d['values'];target=d['target']\n  if values!=sorted(values):raise ValueError('Sorted values required for binary search.')\n  count=0;idx=-1\n  for i,v in enumerate(values):\n   count+=1\n   if v==target:idx=i;break\n  lo,hi=0,len(values)-1;binary=0\n  while lo<=hi:\n   mid=(lo+hi)//2;binary+=1\n   if values[mid]==target:break\n   if values[mid]<target:lo=mid+1\n   else:hi=mid-1\n  return {'index':idx,'linear_comparisons':count,'binary_comparisons':binary}\n if kind=='constraint-planner':\n  valid=[]\n  for slots in itertools.permutations(d['slots'],len(d['tasks'])):\n   plan=dict(zip(d['tasks'],slots))\n   if plan['B']>plan['A'] and plan['C']!=1:valid.append(plan)\n  return {'valid_schedules':len(valid),'selected':valid[0] if valid else None}\n if kind=='maths-workbench':\n  x,rate=d['start'],d['learning_rate']\n  if not numeric(x) or not numeric(rate) or rate<0:raise ValueError('Finite x and non-negative rate required.')\n  g=2*(x-3);n=x-rate*g;return {'gradient':g,'next_x':n,'loss_before':(x-3)**2,'loss_after':(n-3)**2}\n if kind=='api-integration':\n  result=[]\n  for r in d['responses']:\n   status,body=r['status'],r.get('body');result.append('accept_draft' if status==200 and isinstance(body,dict) and isinstance(body.get('text'),str) else 'schema_error' if status==200 else 'bounded_retry_later' if status==429 else 'stop_auth_error' if status in [401,403] else 'unavailable')\n  return {'decisions':result}\n if kind=='augmentation-lab':\n  before=copy.deepcopy(d['test']);aug=copy.deepcopy(d['train'])\n  for row in d['train']:aug.append({**row,'id':row['id']+'-aug','parent':row['id'],'x':row['x']+0.01})\n  return {'original_train':len(d['train']),'augmented_train':len(aug),'unchanged_test':before==d['test'],'unique_originals':len({x['id'] for x in d['train']})}\n if kind=='text-classification':\n  labels=[]\n  for text in d['texts']:\n   tokens=set(re.findall(r'\\b\\w+\\b',text.lower()));a,b='refund' in tokens,'broken' in tokens;labels.append('request' if a and not b else 'issue' if b and not a else 'review')\n  return {'labels':labels,'review_count':labels.count('review')}\n if kind=='uncertainty-lab':\n  v=d['values']\n  if not v or not all(numeric(x) for x in v):raise ValueError('Finite nonempty observations required.')\n  return {'count':len(v),'mean':statistics.mean(v),'minimum':min(v),'maximum':max(v),'range':max(v)-min(v)}\n if kind=='inventory-planning':\n  if not d['demand'] or not all(numeric(x) and x>=0 for x in d['demand']):raise ValueError('Valid demand observations required.')\n  f=statistics.mean(d['demand']);return {'forecast':f,'reorder':max(0,math.ceil(f+d['safety']-d['stock']))}\n if kind=='project-planning':\n  finish={};visiting=set()\n  def end(t):\n   if t in finish:return finish[t]\n   if t in visiting:raise ValueError('Dependency cycle.')\n   visiting.add(t);v=d['duration'][t]+max([end(p) for p in d['depends'][t]] or [0]);visiting.remove(t);finish[t]=v;return v\n  for t in d['duration']:end(t)\n  return {'finish':finish,'project_days':max(finish.values(),default=0)}\n if kind=='supervised-lab':\n  x,y=d['x'],d['y'];mx,my=statistics.mean(x),statistics.mean(y);den=sum((v-mx)**2 for v in x)\n  if not den:raise ValueError('Slope undefined for equal x values.')\n  slope=sum((a-mx)*(b-my) for a,b in zip(x,y))/den;intercept=my-slope*mx;pred=slope*d['test_x']+intercept\n  return {'slope':slope,'intercept':intercept,'prediction':pred,'absolute_error':abs(d['test_y']-pred),'mean_baseline_error':abs(d['test_y']-my)}\n if kind=='preprocessing-lab':\n  observed=[x for x in d['train'] if x is not None]\n  if not observed or not all(numeric(x) for x in observed):raise ValueError('Training mean unavailable.')\n  m=statistics.mean(observed);return {'training_mean':m,'train_filled':[m if x is None else x for x in d['train']],'test_filled':[m if x is None else x for x in d['test']]}\n if kind=='responsible-ai':\n  groups={}\n  for r in d['cases']:groups.setdefault(r['group'],[]).append(r['correct'])\n  return {'group_accuracy':{k:sum(v)/len(v) for k,v in groups.items()},'release':'hold' if d['privacy_failure'] else 'review_residual_risks'}\n if kind=='time-experiment':\n  m=sum(d['manual']);a=sum(d['draft'])+sum(d['check'])+sum(d['rework']);return {'manual_total':m,'assisted_total':a,'saved_minutes':m-a}\n if kind=='data-wrangling':\n  total=0;missing=[]\n  for r in d['orders']:\n   if r['product'] not in d['prices']:missing.append(r['id'])\n   else:total+=r['qty']*d['prices'][r['product']]\n  return {'orders':len(d['orders']),'matched':len(d['orders'])-len(missing),'unmatched':missing,'known_total':total}\n if kind=='sklearn-lab':\n  from sklearn.pipeline import make_pipeline\n  from sklearn.preprocessing import StandardScaler\n  from sklearn.linear_model import LogisticRegression\n  model=make_pipeline(StandardScaler(),LogisticRegression(random_state=7));model.fit(d['train_x'],d['train_y']);pred=model.predict(d['test_x']).tolist();return {'predictions':pred,'correct':sum(a==b for a,b in zip(d['test_y'],pred)),'test_count':len(pred)}\n if kind=='pandas-cleaning':\n  import pandas as pd\n  frame=pd.DataFrame(d['rows']).drop_duplicates(subset=['id'],keep='first').copy();frame['units']=frame['units'].fillna(0);return {'rows':len(frame),'units':frame['units'].tolist(),'total':float(frame['units'].sum()),'outlier_retained':100 in frame['units'].values}\n if kind=='campaign-evidence':return {'ctr':d['clicks']/d['impressions'] if d['impressions'] else None,'cpc':d['spend']/d['clicks'] if d['clicks'] else None,'sales_lift':'not established'}\n if kind=='data-visualisation':\n  failed=[]\n  if d['chart']['axis_min']!=0:failed.append('axis_baseline')\n  if not d['chart'].get('units'):failed.append('units')\n  if not d['chart'].get('alt'):failed.append('text_alternative')\n  return {'total':sum(d['values'].values()),'failed_checks':failed,'release':'revise' if failed else 'inspect_rendered_chart'}\n if kind=='clustering-lab':\n  from sklearn.cluster import KMeans\n  labels=KMeans(n_clusters=2,random_state=7,n_init=10).fit_predict(d['points']);groups={}\n  for id,label in zip(d['ids'],labels):groups.setdefault(int(label),[]).append(id)\n  members=sorted(sorted(v) for v in groups.values());return {'groups':members,'sizes':[len(v) for v in members]}\n if kind=='make-mula':\n  hours=d['delivery_hours']+d['selling_hours']+d['support_hours']\n  if hours<=0:raise ValueError('Positive total hours required.')\n  net=d['price']-d['tool_cost']-d['fees']-d.get('refund',0);return {'net_before_tax':net,'total_hours':hours,'effective_hourly_before_tax':net/hours}\n raise ValueError('Unknown reference project.')\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import json\n",
        "fixture=json.loads('{\\n  \"texts\": [\\n    \"please refund my order\",\\n    \"the item is broken\",\\n    \"refund this broken item\",\\n    \"hello there\"\\n  ]\\n}')\n",
        "expected=json.loads('{\\n  \"labels\": [\\n    \"request\",\\n    \"issue\",\\n    \"review\",\\n    \"review\"\\n  ],\\n  \"review_count\": 2\\n}')\n",
        "actual=run('text-classification',fixture)\n",
        "assert actual==expected,(actual,expected)\n",
        "actual"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Your independent change tests\n",
        "- Not broken still contains the token broken: document the baseline failure.\n- Add punctuation: tokenisation should preserve the intended word boundary.\n- Try another language: abstain and obtain appropriate evaluation before use.",
        "\nAdd cells with predictions and observed results. Do not overwrite the original fixture."
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
